diff --git a/src/main/java/dev/brighten/ac/Anticheat.java b/src/main/java/dev/brighten/ac/Anticheat.java index 9fa594e..616f491 100644 --- a/src/main/java/dev/brighten/ac/Anticheat.java +++ b/src/main/java/dev/brighten/ac/Anticheat.java @@ -68,8 +68,6 @@ public class Anticheat extends JavaPlugin { .setNameFormat("Anticheat Schedular") .setUncaughtExceptionHandler((t, e) -> RunUtils.task(e::printStackTrace)) .build()); - packetProcessor = new PacketProcessor(); - HandlerAbstract.init(); commandManager = new BukkitCommandManager(this); commandManager.enableUnstableAPI("help"); @@ -77,11 +75,14 @@ public class Anticheat extends JavaPlugin { new CommandPropertiesManager(commandManager, getDataFolder(), getResource("command-messages.properties")); + this.keepaliveProcessor = new KeepaliveProcessor(); + packetProcessor = new PacketProcessor(); this.checkManager = new CheckManager(); this.playerRegistry = new PlayerRegistry(); - this.keepaliveProcessor = new KeepaliveProcessor(); this.packetHandler = new PacketHandler(); + HandlerAbstract.init(); + alog(Color.Green + "Loading WorldInfo system..."); Bukkit.getWorlds().forEach(w -> worldInfoMap.put(w.getUID(), new WorldInfo(w))); diff --git a/src/main/java/dev/brighten/ac/check/impl/combat/Aim.java b/src/main/java/dev/brighten/ac/check/impl/combat/Aim.java new file mode 100644 index 0000000..aa2fe77 --- /dev/null +++ b/src/main/java/dev/brighten/ac/check/impl/combat/Aim.java @@ -0,0 +1,99 @@ +package dev.brighten.ac.check.impl.combat; + +import dev.brighten.ac.check.Action; +import dev.brighten.ac.check.Check; +import dev.brighten.ac.check.CheckData; +import dev.brighten.ac.check.CheckType; +import dev.brighten.ac.data.APlayer; +import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying; +import dev.brighten.ac.utils.timer.Timer; +import dev.brighten.ac.utils.timer.impl.TickTimer; + +import java.util.List; + +@CheckData(name = "Aim", type = CheckType.COMBAT) +public class Aim extends Check { + public Aim(APlayer player) { + super(player); + } + + private float buffer; + protected Timer lastGrid = new TickTimer(3); + + @Action + public void flying(WPacketPlayInFlying packet) { + if(!packet.isLooked()) return; + + final float sens = getPlayer().getMovement().getSensitivityMcp(), + deltaYaw = Math.abs(getPlayer().getMovement().getDeltaYaw()), + deltaPitch = Math.abs(getPlayer().getMovement().getDeltaPitch()); + final float deltaX = deltaYaw / getPlayer().getMovement().getYawMode(); + final float deltaY = deltaPitch / getPlayer().getMovement().getPitchMode(); + + if(getPlayer().getMovement().getYawGcdList().size() < 40) + return; + + final double gridX = getGrid(getPlayer().getMovement().getYawGcdList()), + gridY = getGrid(getPlayer().getMovement().getPitchGcdList()); + + if(gridX < 0.005 || gridY < 0.005) lastGrid.reset(); + + if(deltaX > 200 || deltaY > 200) { + if(buffer > 0) buffer--; + getPlayer().getBukkitPlayer().sendMessage("Unstable"); + return; + } + + if(getPlayer().getMovement().getPitchGCD() < 0.007 + && lastGrid.isPassed() + && getPlayer().getMovement().getLastHighRate().isNotPassed(3)) { + if(deltaPitch < 10 && ++buffer > 8) { + flag("%s", getPlayer().getMovement().getPitchGCD()); + } + getPlayer().getBukkitPlayer().sendMessage("Flagged b:" + buffer); + } else buffer = 0; + } + + /* + * This is an attempt to reverse the logistics of cinematic camera without having to run a full on prediction using + * mouse filters. Otherwise, we would need to run more heavy calculations which is not really production friendly. + * It may be more accurate but it is not really worth it if in the end of the day we're eating server performance. + */ + protected static double getGrid(final List entry) { + /* + * We're creating the variables average min and max to start calculating the possibility of cinematic camera. + * Why does this work? Cinematic camera is essentially a slowly increasing slowdown (which is why cinematic camera + * becomes slower the more you use it) which in turn makes it so the min max and average are extremely close together. + */ + double average = 0.0; + double min = 0.0, max = 0.0; + + /* + * These are simple min max calculations done manually for the sake of simplicity. We're using the numbers 0.0 + * since we also want to account for the possibility of a negative number. If there are no negative numbers then + * there is absolutely no need for us to care about that number other than getting the max. + */ + for (final double number : entry) { + if (number < min) min = number; + if (number > max) max = number; + + /* + * Instead of having a sum variable we can use an average variable which we divide + * right after the loop is over. Smart programming trick if you want to use it. + */ + average += number; + } + + /* + * We're dividing the average by the length since this is the formula to getting the average. + * Specifically its (sum(n) / length(n)) = average(n) -- with n being the entry set we're analyzing. + */ + average /= entry.size(); + + /* + * This is going to estimate how close the average and the max were together with the possibility of a min + * variable which is going to represent a negative variable since the preset variable on min is 0.0. + */ + return (max - average) - min; + } +} diff --git a/src/main/java/dev/brighten/ac/check/impl/combat/Reach.java b/src/main/java/dev/brighten/ac/check/impl/combat/Reach.java index 10d2dcc..ab21149 100644 --- a/src/main/java/dev/brighten/ac/check/impl/combat/Reach.java +++ b/src/main/java/dev/brighten/ac/check/impl/combat/Reach.java @@ -40,7 +40,6 @@ public class Reach extends Check { if(packet.getAction() == WPacketPlayInUseEntity.EnumEntityUseAction.ATTACK && allowedEntityTypes.contains(packet.getEntity(getPlayer().getBukkitPlayer().getWorld()).getType())) { attacks.add(packet.getEntity(getPlayer().getBukkitPlayer().getWorld())); - getPlayer().getBukkitPlayer().sendMessage("Attacked"); } } diff --git a/src/main/java/dev/brighten/ac/check/impl/fly/FlyA.java b/src/main/java/dev/brighten/ac/check/impl/fly/FlyA.java index b5b0a77..99c7ba1 100644 --- a/src/main/java/dev/brighten/ac/check/impl/fly/FlyA.java +++ b/src/main/java/dev/brighten/ac/check/impl/fly/FlyA.java @@ -26,8 +26,8 @@ public class FlyA extends Check { @Action public void onFlying(WPacketPlayInFlying packet) { if(!packet.isMoved() || (getPlayer().getMovement().getDeltaXZ() == 0 - && getPlayer().getMovement().getDeltaY() == 0)) return; - + && getPlayer().getMovement().getDeltaY() == 0)) + return; boolean onGround = getPlayer().getMovement().getTo().isOnGround(), fromGround = getPlayer().getMovement().getFrom().isOnGround(); @@ -55,6 +55,7 @@ public class FlyA extends Check { if(!getPlayer().getInfo().isGeneralCancel() && deltaPredict > 0.016) { if(++buffer > 5) { + buffer = 5; flag("dY=%.3f p=%.3f dx=%.3f", getPlayer().getMovement().getDeltaY(), predicted, getPlayer().getMovement().getDeltaXZ()); } diff --git a/src/main/java/dev/brighten/ac/check/impl/speed/Speed.java b/src/main/java/dev/brighten/ac/check/impl/speed/Speed.java index 0d3ff98..d8e981f 100644 --- a/src/main/java/dev/brighten/ac/check/impl/speed/Speed.java +++ b/src/main/java/dev/brighten/ac/check/impl/speed/Speed.java @@ -35,10 +35,8 @@ public class Speed extends Check { .toLocation(getPlayer().getBukkitPlayer().getWorld()) .subtract(0, 1, 0)); - if (underBlock == null || lastUnderBlock == null) { - getPlayer().getBukkitPlayer().sendMessage("Null"); + if (underBlock == null || lastUnderBlock == null) return; - } float friction = CraftMagicNumbers.getBlock(underBlock).frictionFactor, lfriction = CraftMagicNumbers.getBlock(lastUnderBlock).frictionFactor; diff --git a/src/main/java/dev/brighten/ac/command/AnticheatCommand.java b/src/main/java/dev/brighten/ac/command/AnticheatCommand.java index 7717934..9bd5a8a 100644 --- a/src/main/java/dev/brighten/ac/command/AnticheatCommand.java +++ b/src/main/java/dev/brighten/ac/command/AnticheatCommand.java @@ -92,6 +92,7 @@ public class AnticheatCommand extends BaseCommand { sender.sendMessage(MiscUtils.line(Color.Dark_Gray)); sender.sendMessage(Color.translate("&6&lPing&8: &f" + player.getLagInfo().getTransPing() * 50 + "ms")); sender.sendMessage(Color.translate("&6&lVersion&8: &f" + player.getPlayerVersion().name())); + sender.sendMessage(Color.translate("&6&lSensitivity&8: &f" + player.getMovement().getSensXPercent() + "%")); sender.sendMessage(MiscUtils.line(Color.Dark_Gray)); }); } diff --git a/src/main/java/dev/brighten/ac/data/APlayer.java b/src/main/java/dev/brighten/ac/data/APlayer.java index 0c27dec..d8ee844 100644 --- a/src/main/java/dev/brighten/ac/data/APlayer.java +++ b/src/main/java/dev/brighten/ac/data/APlayer.java @@ -19,6 +19,8 @@ import dev.brighten.ac.packet.handler.HandlerAbstract; import dev.brighten.ac.utils.Tuple; import dev.brighten.ac.utils.reflections.impl.MinecraftReflection; import dev.brighten.ac.utils.reflections.types.WrappedMethod; +import dev.brighten.ac.utils.timer.Timer; +import dev.brighten.ac.utils.timer.impl.MillisTimer; import lombok.Getter; import lombok.Setter; import lombok.val; @@ -52,6 +54,8 @@ public class APlayer { @Getter private int playerTick; @Getter + private Timer creation = new MillisTimer(); + @Getter //TODO Actually grab real player version once finished implementing version grabber from Atlas private ProtocolVersion playerVersion = ProtocolVersion.UNKNOWN; @Getter @@ -87,9 +91,11 @@ public class APlayer { this.lagInfo = new LagInformation(); this.blockInformation = new BlockInformation(this); + // Grabbing the protocol version of the player. Anticheat.INSTANCE.getScheduler().execute(() -> playerVersion = ProtocolVersion.getVersion(ProtocolAPI.INSTANCE.getPlayerVersion(getBukkitPlayer()))); + // Enabling alerts for players on join if they have the permissions to if(getBukkitPlayer().hasPermission("anticheat.command.alerts") || getBukkitPlayer().hasPermission("anticheat.alerts")) { Check.alertsEnabled.add(getUuid()); diff --git a/src/main/java/dev/brighten/ac/data/handlers/MovementHandler.java b/src/main/java/dev/brighten/ac/data/handlers/MovementHandler.java index 321de46..7a219b9 100644 --- a/src/main/java/dev/brighten/ac/data/handlers/MovementHandler.java +++ b/src/main/java/dev/brighten/ac/data/handlers/MovementHandler.java @@ -14,6 +14,7 @@ import dev.brighten.ac.utils.world.types.SimpleCollisionBox; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.Setter; +import lombok.val; import org.bukkit.GameMode; import org.bukkit.Location; @@ -33,22 +34,35 @@ public class MovementHandler { private double deltaX, deltaY, deltaZ, deltaXZ, lDeltaX, lDeltaY, lDeltaZ, lDeltaXZ; @Getter - private float deltaYaw, deltaPitch, lDeltaYaw, lDeltaPitch; + private float lookX, lookY, lastLookX, lastLookY; + @Getter + private float deltaYaw, deltaPitch, lDeltaYaw, lDeltaPitch, smoothYaw, smoothPitch, lsmoothYaw, lsmoothPitch, pitchGCD, lastPitchGCD, yawGCD, lastYawGCD; private int moveTicks; private final List posLocs = new ArrayList<>(); @Getter - private boolean checkMovement; + private boolean checkMovement, accurateYawData, cinematicMode; @Getter @Setter private boolean excuseNextFlying; @Getter - private final Timer lastTeleport = new TickTimer(); + private final Timer lastTeleport = new TickTimer(), lastHighRate = new TickTimer(); private int teleportsToConfirm; + @Getter private final LinkedList yawGcdList = new EvictingList<>(45), pitchGcdList = new EvictingList<>(45); + @Getter + private float sensitivityX, sensitivityY, currentSensX, currentSensY, sensitivityMcp, yawMode, pitchMode; + @Getter + private int sensXPercent, sensYPercent; + @Getter + private TickTimer lastCinematic = new TickTimer(2); + private MouseFilter mxaxis = new MouseFilter(), myaxis = new MouseFilter(); + private float smoothCamFilterX, smoothCamFilterY, smoothCamYaw, smoothCamPitch; + private Timer lastReset = new TickTimer(2), generalProcess = new TickTimer(3); + private final EvictingList sensitivitySamples = new EvictingList<>(50); public void process(WPacketPlayInFlying packet, long currentTime) { @@ -82,6 +96,132 @@ public class MovementHandler { checkForTeleports(packet); + if (packet.isLooked()) { + float deltaYaw = Math.abs(this.deltaYaw), lastDeltaYaw = Math.abs(this.lDeltaYaw); + final double differenceYaw = Math.abs(this.deltaYaw - lastDeltaYaw); + final double differencePitch = Math.abs(this.deltaPitch - this.lDeltaPitch); + + final double joltYaw = Math.abs(differenceYaw - deltaYaw); + final double joltPitch = Math.abs(differencePitch - this.deltaPitch); + + final float yawThreshold = Math.max(1.0f, deltaYaw / 2f), + pitchThreshold = Math.max(1.f, Math.abs(this.deltaPitch) / 2f); + + if (joltYaw > yawThreshold && joltPitch > pitchThreshold) this.lastHighRate.reset(); + this.lastPitchGCD = this.pitchGCD; + this.lastYawGCD = this.yawGCD; + this.yawGCD = MathUtils + .gcdSmall(this.deltaYaw, this.lDeltaYaw); + this.pitchGCD = MathUtils + .gcdSmall(this.deltaPitch, this.lDeltaPitch); + + val origin = this.to.getLoc().clone(); + + origin.y+= player.getInfo().isSneaking() ? 1.54 : 1.62; + + if(lastTeleport.isPassed(1)) { + predictionHandling: + { + float yawGcd = this.yawGCD, + pitchGcd = this.pitchGCD; + + //Adding gcd of yaw and pitch. + if (this.yawGCD > 0.01 && this.yawGCD < 1.2) { + yawGcdList.add(yawGcd); + } + if (this.pitchGCD > 0.01 && this.pitchGCD < 1.2) + pitchGcdList.add(pitchGcd); + + if(yawGcdList.size() < 20 || pitchGcdList.size() < 20) { + accurateYawData = false; + break predictionHandling; + } + + accurateYawData = true; + + //Making sure to get shit within the std for a more accurate result. + + //Making sure to get shit within the std for a more accurate result. + currentSensX = getSensitivityFromYawGCD(yawGcd); + currentSensY = getSensitivityFromPitchGCD(pitchGcd); + if (lastReset.isPassed()) { + pitchMode = MathUtils.getMode(pitchGcdList); + lastReset.reset(); + sensXPercent = sensToPercent(sensitivityX = getSensitivityFromYawGCD(yawMode)); + sensYPercent = sensToPercent(sensitivityY = getSensitivityFromPitchGCD(pitchMode)); + + table: { + sensitivitySamples.add(Math.max(sensXPercent, sensYPercent)); + + if (sensitivitySamples.size() > 30) { + final long mode = MathUtils.getMode(sensitivitySamples); + + sensitivityMcp = AimbotUtil.SENSITIVITY_MAP.getOrDefault((int) mode, -1.0F); + } + } + } + + + lastLookX = lookX; + lastLookY = lookY; + lookX = getExpiermentalDeltaX(player); + lookY = getExpiermentalDeltaY(player); + + if ((this.pitchGCD < 0.006 && this.yawGCD < 0.006) && smoothCamFilterY < 1E6 + && smoothCamFilterX < 1E6 && player.getCreation().isPassed(1000L)) { + float sens = MovementHandler.percentToSens(95); + float f = sens * 0.6f + .2f; + float f1 = f * f * f * 8; + float f2 = lookX * f1; + float f3 = lookY * f1; + + smoothCamFilterX = mxaxis.smooth(smoothCamYaw, .05f * f1); + smoothCamFilterY = myaxis.smooth(smoothCamPitch, .05f * f1); + + this.smoothCamYaw += f2; + this.smoothCamPitch += f3; + + f2 = smoothCamFilterX * 0.5f; + f3 = smoothCamFilterY * 0.5f; + + //val clampedFrom = (Math.abs(this.from.yaw) > 360 ? this.from.yaw % 360 : this.from.yaw); + val clampedFrom = MathUtils.yawTo180F(getFrom().getLoc().yaw); + float pyaw = clampedFrom + f2 * .15f; + float ppitch = this.getFrom().getLoc().pitch - f3 * .15f; + + this.lsmoothYaw = smoothYaw; + this.lsmoothPitch = smoothPitch; + this.smoothYaw = pyaw; + this.smoothPitch = ppitch; + + float yaccel = Math.abs(this.deltaYaw) - Math.abs(this.lDeltaYaw), + pAccel = Math.abs(this.deltaPitch) - Math.abs(this.lDeltaPitch); + + if (MathUtils.getDelta(smoothYaw, clampedFrom) > (yaccel > 0 ? (yaccel > 10 ? 2.5 : 1) : 0.3) + || MathUtils.getDelta(smoothPitch, this.getFrom().getLoc().pitch) + > (pAccel > 0 ? (pAccel > 10 ? 2.5 : 1) : 0.3)) { + smoothCamYaw = smoothCamPitch = 0; + this.cinematicMode = false; + mxaxis.reset(); + myaxis.reset(); + } else this.cinematicMode = true; + } else { + mxaxis.reset(); + myaxis.reset(); + this.cinematicMode = false; + } + + lastLookX = lookX; + lastLookY = lookY; + lookX = getExpiermentalDeltaX(player); + lookY = getExpiermentalDeltaY(player); + } + } else { + yawGcdList.clear(); + pitchGcdList.clear(); + } + } + player.getInfo().setCreative(player.getBukkitPlayer().getGameMode() == GameMode.CREATIVE || player.getBukkitPlayer().getGameMode() == GameMode.SPECTATOR); @@ -103,27 +243,104 @@ public class MovementHandler { /* ata.playerInfo.generalCancel = data.getPlayer().getAllowFlight() - || data.playerInfo.creative + || this.creative || hasLevi || data.excuseNextFlying || data.getPlayer().isSleeping() - || (data.playerInfo.lastGhostCollision.isNotPassed() && data.playerInfo.lastBlockPlace.isPassed(2)) - || data.playerInfo.doingTeleport - || data.playerInfo.lastTeleportTimer.isNotPassed(1) - || data.playerInfo.riptiding - || data.playerInfo.gliding - || data.playerInfo.vehicleTimer.isNotPassed(3) - || data.playerInfo.lastPlaceLiquid.isNotPassed(5) - || data.playerInfo.inVehicle - || ((data.playerInfo.lastChunkUnloaded.isNotPassed(35) || data.playerInfo.doingBlockUpdate) - && MathUtils.getDelta(-0.098, data.playerInfo.deltaY) < 0.0001) - || timeStamp - data.playerInfo.lastRespawn < 2500L - || data.playerInfo.lastToggleFlight.isNotPassed(40) + || (this.lastGhostCollision.isNotPassed() && this.lastBlockPlace.isPassed(2)) + || this.doingTeleport + || this.lastTeleportTimer.isNotPassed(1) + || this.riptiding + || this.gliding + || this.vehicleTimer.isNotPassed(3) + || this.lastPlaceLiquid.isNotPassed(5) + || this.inVehicle + || ((this.lastChunkUnloaded.isNotPassed(35) || this.doingBlockUpdate) + && MathUtils.getDelta(-0.098, this.deltaY) < 0.0001) + || timeStamp - this.lastRespawn < 2500L + || this.lastToggleFlight.isNotPassed(40) || timeStamp - data.creation < 4000 || Kauri.INSTANCE.lastTickLag.isNotPassed(5); */ } + private static float getDeltaX(float yawDelta, float gcd) { + return MathHelper.ceiling_float_int(yawDelta / gcd); + } + + private static float getDeltaY(float pitchDelta, float gcd) { + return MathHelper.ceiling_float_int(pitchDelta / gcd); + } + + public static float getExpiermentalDeltaX(APlayer data) { + float deltaPitch = data.getMovement().getDeltaYaw(); + float sens = data.getMovement().sensitivityX; + float f = sens * 0.6f + .2f; + float calc = f * f * f * 8; + + float result = deltaPitch / (calc * .15f); + + return result; + } + + public static float getExpiermentalDeltaY(APlayer data) { + float deltaPitch = data.getMovement().getDeltaPitch(); + float sens = data.getMovement().sensitivityY; + float f = sens * 0.6f + .2f; + float calc = f * f * f * 8; + + float result = deltaPitch / (calc * .15f); + + return result; + } + + public static int sensToPercent(float sensitivity) { + return MathHelper.floor_float(sensitivity / .5f * 100); + } + + public static float percentToSens(int percent) { + return percent * .0070422534f; + } + + public static float getSensitivityFromYawGCD(float gcd) { + return ((float) Math.cbrt(yawToF2(gcd) / 8f) - .2f) / .6f; + } + + private static float getSensitivityFromPitchGCD(float gcd) { + return ((float)Math.cbrt(pitchToF3(gcd) / 8f) - .2f) / .6f; + } + + private static float getF1FromYaw(float gcd) { + float f = getFFromYaw(gcd); + + return f * f * f * 8; + } + + private static float getFFromYaw(float gcd) { + float sens = getSensitivityFromYawGCD(gcd); + return sens * .6f + .2f; + } + + private static float getFFromPitch(float gcd) { + float sens = getSensitivityFromPitchGCD(gcd); + return sens * .6f + .2f; + } + + private static float getF1FromPitch(float gcd) { + float f = getFFromPitch(gcd); + + return (float)Math.pow(f, 3) * 8; + } + + private static float yawToF2(float yawDelta) { + return yawDelta / .15f; + } + + private static float pitchToF3(float pitchDelta) { + int b0 = pitchDelta >= 0 ? 1 : -1; //Checking for inverted mouse. + return (pitchDelta / b0) / .15f; + } + public void addPosition(WPacketPlayOutPosition packet) { int i = 0; KLocation loc = new KLocation(packet.getX(), packet.getY(), packet.getZ(), @@ -241,7 +458,7 @@ public class MovementHandler { deltaY = to.getLoc().y - from.getLoc().y; deltaZ = to.getLoc().z - from.getLoc().z; deltaXZ = Math.hypot(deltaX, deltaZ); // Calculating here to cache since hypot() can be heavy. - deltaYaw = MathUtils.getAngleDelta(to.getLoc().yaw, from.getLoc().yaw); + deltaYaw = to.getLoc().yaw - from.getLoc().yaw; deltaPitch = to.getLoc().pitch - from.getLoc().pitch; } } diff --git a/src/main/java/dev/brighten/ac/listener/JoinListener.java b/src/main/java/dev/brighten/ac/listener/JoinListener.java index e8aabb2..52350ba 100644 --- a/src/main/java/dev/brighten/ac/listener/JoinListener.java +++ b/src/main/java/dev/brighten/ac/listener/JoinListener.java @@ -6,6 +6,7 @@ import dev.brighten.ac.handler.thread.ThreadHandler; import dev.brighten.ac.packet.handler.HandlerAbstract; import dev.brighten.ac.packet.wrapper.PacketType; import dev.brighten.ac.utils.Init; +import dev.brighten.ac.utils.RunUtils; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -74,10 +75,9 @@ public class JoinListener implements Listener { @EventHandler public void onJoin(PlayerJoinEvent event) { - System.out.println("Generating for " + event.getPlayer().getName()); APlayer player = Anticheat.INSTANCE.getPlayerRegistry().generate(event.getPlayer()); - HandlerAbstract.getHandler().add(event.getPlayer()); + RunUtils.taskLater(() -> HandlerAbstract.getHandler().add(event.getPlayer()), 3); player.callEvent(event); } diff --git a/src/main/java/dev/brighten/ac/utils/AimbotUtil.java b/src/main/java/dev/brighten/ac/utils/AimbotUtil.java new file mode 100644 index 0000000..8b0b7e0 --- /dev/null +++ b/src/main/java/dev/brighten/ac/utils/AimbotUtil.java @@ -0,0 +1,324 @@ +package dev.brighten.ac.utils; + +import com.google.common.collect.Maps; + +import java.util.List; +import java.util.Map; + +public class AimbotUtil { + public static final Map SENSITIVITY_MAP = Maps.newHashMap(); + + static { + SENSITIVITY_MAP.put(1, 0.0070422534F); + SENSITIVITY_MAP.put(2, 0.014084507F); + SENSITIVITY_MAP.put(4, 0.02112676F); + SENSITIVITY_MAP.put(5, 0.028169014F); + SENSITIVITY_MAP.put(6, 0.0281690166F); + SENSITIVITY_MAP.put(7, 0.03521127F); + SENSITIVITY_MAP.put(8, 0.04225352F); + SENSITIVITY_MAP.put(9, 0.049295776F); + SENSITIVITY_MAP.put(10, 0.0492957736F); + SENSITIVITY_MAP.put(11, 0.056338027F); + SENSITIVITY_MAP.put(12, 0.06338028F); + SENSITIVITY_MAP.put(14, 0.07042254F); + SENSITIVITY_MAP.put(15, 0.07746479F); + SENSITIVITY_MAP.put(16, 0.08450704F); + SENSITIVITY_MAP.put(18, 0.09154929F); + SENSITIVITY_MAP.put(19, 0.09859155F); + SENSITIVITY_MAP.put(21, 0.1056338F); + SENSITIVITY_MAP.put(22, 0.112676054F); + SENSITIVITY_MAP.put(23, 0.11971831F); + SENSITIVITY_MAP.put(25, 0.12676056F); + SENSITIVITY_MAP.put(26, 0.13380282F); + SENSITIVITY_MAP.put(28, 0.14084508F); + SENSITIVITY_MAP.put(29, 0.14788732F); + SENSITIVITY_MAP.put(30, 0.15492958F); + SENSITIVITY_MAP.put(32, 0.16197184F); + SENSITIVITY_MAP.put(33, 0.16901408F); + SENSITIVITY_MAP.put(35, 0.17605634F); + SENSITIVITY_MAP.put(36, 0.18309858F); + SENSITIVITY_MAP.put(38, 0.19014084F); + SENSITIVITY_MAP.put(39, 0.1971831F); + SENSITIVITY_MAP.put(40, 0.20422535F); + SENSITIVITY_MAP.put(42, 0.2112676F); + SENSITIVITY_MAP.put(43, 0.21830986F); + SENSITIVITY_MAP.put(45, 0.22535211F); + SENSITIVITY_MAP.put(46, 0.23239437F); + SENSITIVITY_MAP.put(47, 0.23943663F); + SENSITIVITY_MAP.put(49, 0.24647887F); + SENSITIVITY_MAP.put(50, 0.2535211F); + SENSITIVITY_MAP.put(52, 0.26056337F); + SENSITIVITY_MAP.put(53, 0.26760563F); + SENSITIVITY_MAP.put(54, 0.2746479F); + SENSITIVITY_MAP.put(56, 0.28169015F); + SENSITIVITY_MAP.put(57, 0.28873238F); + SENSITIVITY_MAP.put(59, 0.29577464F); + SENSITIVITY_MAP.put(60, 0.3028169F); + SENSITIVITY_MAP.put(61, 0.30985916F); + SENSITIVITY_MAP.put(63, 0.31690142F); + SENSITIVITY_MAP.put(64, 0.32394367F); + SENSITIVITY_MAP.put(66, 0.3309859F); + SENSITIVITY_MAP.put(67, 0.33802816F); + SENSITIVITY_MAP.put(68, 0.34507042F); + SENSITIVITY_MAP.put(70, 0.35211268F); + SENSITIVITY_MAP.put(71, 0.35915494F); + SENSITIVITY_MAP.put(73, 0.36619717F); + SENSITIVITY_MAP.put(74, 0.37323943F); + SENSITIVITY_MAP.put(76, 0.3802817F); + SENSITIVITY_MAP.put(77, 0.38732395F); + SENSITIVITY_MAP.put(78, 0.3943662F); + SENSITIVITY_MAP.put(80, 0.40140846F); + SENSITIVITY_MAP.put(81, 0.4084507F); + SENSITIVITY_MAP.put(83, 0.41549295F); + SENSITIVITY_MAP.put(84, 0.4225352F); + SENSITIVITY_MAP.put(85, 0.42957747F); + SENSITIVITY_MAP.put(87, 0.43661973F); + SENSITIVITY_MAP.put(88, 0.44366196F); + SENSITIVITY_MAP.put(90, 0.45070422F); + SENSITIVITY_MAP.put(91, 0.45774648F); + SENSITIVITY_MAP.put(92, 0.46478873F); + SENSITIVITY_MAP.put(94, 0.471831F); + SENSITIVITY_MAP.put(95, 0.47887325F); + SENSITIVITY_MAP.put(97, 0.48591548F); + SENSITIVITY_MAP.put(98, 0.49295774F); + SENSITIVITY_MAP.put(100, 0.5F); + SENSITIVITY_MAP.put(101, 0.5070422F); + SENSITIVITY_MAP.put(102, 0.5140845F); + SENSITIVITY_MAP.put(104, 0.52112675F); + SENSITIVITY_MAP.put(105, 0.52816904F); + SENSITIVITY_MAP.put(107, 0.53521127F); + SENSITIVITY_MAP.put(108, 0.5422535F); + SENSITIVITY_MAP.put(109, 0.5492958F); + SENSITIVITY_MAP.put(111, 0.556338F); + SENSITIVITY_MAP.put(112, 0.5633803F); + SENSITIVITY_MAP.put(114, 0.57042253F); + SENSITIVITY_MAP.put(115, 0.57746476F); + SENSITIVITY_MAP.put(116, 0.58450705F); + SENSITIVITY_MAP.put(118, 0.5915493F); + SENSITIVITY_MAP.put(119, 0.59859157F); + SENSITIVITY_MAP.put(121, 0.6056338F); + SENSITIVITY_MAP.put(122, 0.6126761F); + SENSITIVITY_MAP.put(123, 0.6197183F); + SENSITIVITY_MAP.put(125, 0.62676054F); + SENSITIVITY_MAP.put(126, 0.63380283F); + SENSITIVITY_MAP.put(128, 0.64084506F); + SENSITIVITY_MAP.put(129, 0.647887350F); + SENSITIVITY_MAP.put(130, 0.6549296F); + SENSITIVITY_MAP.put(132, 0.6619718F); + SENSITIVITY_MAP.put(133, 0.6690141F); + SENSITIVITY_MAP.put(135, 0.6760563F); + SENSITIVITY_MAP.put(136, 0.6830986F); + SENSITIVITY_MAP.put(138, 0.69014084F); + SENSITIVITY_MAP.put(139, 0.6971831F); + SENSITIVITY_MAP.put(140, 0.70422536F); + SENSITIVITY_MAP.put(142, 0.7112676F); + SENSITIVITY_MAP.put(143, 0.7183099F); + SENSITIVITY_MAP.put(145, 0.7253521F); + SENSITIVITY_MAP.put(146, 0.73239434F); + SENSITIVITY_MAP.put(147, 0.7394366F); + SENSITIVITY_MAP.put(149, 0.74647886F); + SENSITIVITY_MAP.put(150, 0.75352114F); + SENSITIVITY_MAP.put(152, 0.7605634F); + SENSITIVITY_MAP.put(153, 0.76760566F); + SENSITIVITY_MAP.put(154, 0.7746479F); + SENSITIVITY_MAP.put(156, 0.7816901F); + SENSITIVITY_MAP.put(157, 0.7887324F); + SENSITIVITY_MAP.put(159, 0.79577464F); + SENSITIVITY_MAP.put(160, 0.8028169F); + SENSITIVITY_MAP.put(161, 0.80985916F); + SENSITIVITY_MAP.put(163, 0.8169014F); + SENSITIVITY_MAP.put(164, 0.8239437F); + SENSITIVITY_MAP.put(166, 0.8309859F); + SENSITIVITY_MAP.put(167, 0.8380282F); + SENSITIVITY_MAP.put(169, 0.8450704F); + SENSITIVITY_MAP.put(170, 0.85211265F); + SENSITIVITY_MAP.put(171, 0.85915494F); + SENSITIVITY_MAP.put(173, 0.86619717F); + SENSITIVITY_MAP.put(174, 0.87323946F); + SENSITIVITY_MAP.put(176, 0.8802817F); + SENSITIVITY_MAP.put(177, 0.8873239F); + SENSITIVITY_MAP.put(178, 0.8943662F); + SENSITIVITY_MAP.put(180, 0.90140843F); + SENSITIVITY_MAP.put(181, 0.9084507F); + SENSITIVITY_MAP.put(183, 0.91549295F); + SENSITIVITY_MAP.put(184, 0.92253524F); + SENSITIVITY_MAP.put(185, 0.92957747F); + SENSITIVITY_MAP.put(187, 0.9366197F); + SENSITIVITY_MAP.put(188, 0.943662F); + SENSITIVITY_MAP.put(190, 0.9507042F); + SENSITIVITY_MAP.put(191, 0.9577465F); + SENSITIVITY_MAP.put(192, 0.96478873F); + SENSITIVITY_MAP.put(194, 0.97183096F); + SENSITIVITY_MAP.put(195, 0.97887325F); + SENSITIVITY_MAP.put(197, 0.9859155F); + SENSITIVITY_MAP.put(198, 0.9929578F); + SENSITIVITY_MAP.put(200, 1.0F); + } + + /* + * Essentially what we're doing here is enclosing the possible rotations the player + * would've made in a normal framed scenario. The problem with the method we're using + * to verify the player's rotation (prediction) has one problem. And that problem is + * frame updates or as the client calls them "partial ticks". With this method, we can + * directly check if the player's rotation was in the range of possible values, and we can + * get that range with a simple limit check by complying the prediction vs the rotation + * + * Essentially it accounts for rotations that couldn't have been accurately predicted because + * they got updated many times outside of the tick. + */ + public static boolean enclosed(final float a, final float b, final float x) { + final float distance = MathUtils.getAngleDelta(a, b); + + return MathUtils.getAngleDelta(a, x) < distance && MathUtils.getAngleDelta(b, x) < distance; + } + + /* + * This gets the players sensitivity through reversing the GCD of the player which + * is the constant of the past 40 rotations, directly using minecraft math to achieve that. + * + * // Update the mouse position per frame + * this.mouseHelper.updateXY(); + * + * // Grab the new deltaXY mouse values made + * final int deltaX = mouseHelper.getX(); + * final int deltaY = mouseHelper.getY(); + * + * // Run the sensitivity formula to construct the new yaw/pitch values + * final float sensitivityFormat = (float) sensitivity * 0.6F + 0.2F; + * final float sensitivityProduct = var132 * var132 * var132 * 8.0F; + * + * // Run the construction formula for yaw and pitch + * final float constructedYaw = (float) deltaX * sensitivityFormat; + * final float constructedPitch = (float) deltaY * sensitivityFormat + * + * // Account for rotation slowdown using the 0.15 as a constant number + * final float productYaw = Math.abs(rotationYaw) + constructedYaw * 0.15 + * final float productPitch = Math.abs(rotationPitch) + constructedPitch * 0.15 + * + * // Account for inversion + * this.rotationYaw = productYaw * inverseYaw; + * this.rotationPitch = productPitch * inversePitch; + */ + public static float getSensitivityFromYawGCD(float gcd) { + return ((float)Math.cbrt(yawToF2(gcd) / 8f) - .2f) / .6f; + } + + public static float getSensitivityFromPitchGCD(float gcd) { + return ((float)Math.cbrt(pitchToF3(gcd) / 8f) - .2f) / .6f; + } + + private static float yawToF2(float yawDelta) { + return yawDelta / .15f; + } + + private static float pitchToF3(float pitchDelta) { + int b0 = pitchDelta >= 0 ? 1 : -1; //Checking for inverted mouse. + return (pitchDelta / b0) / .15f; + } + + /* + * This is going to be used for our inverse method for rotations since the method we are currently + * using for inverse is a little inaccurate in some places due to the implementation of the game. + * This should have a non existent margin of error since it will always be accurate to the degree. + */ + private static float toRegularCircle(float angles) { + angles %= 360.F; + return angles < 0 ? angles + 360.F : angles; + } + + public static int getInverseValue(final float current, final float previous, final InverseType type) { + int result; + /* + * We're not using a switch statement since there is only really two possibilities so a switch + * statement for my taste would simply be a little messy. + */ + if (type == InverseType.YAW) { + final float distance = MathUtils.getAngleDelta(previous, current); + + /* + * We're expressing it as a regular circle since there is not a real limit to how the yaw is expressed + * meaning if we do the check dynamically like we used to, it will fail when resetting or on larger rotations + */ + final float circleX = toRegularCircle(previous); + final float circleY = toRegularCircle(current); + + /* + * This is the valid expression to the delta which is going to help us understand the direction + * the player moved their head to get a more valid reading on their inversion. + */ + final double polarX = MathUtils.getAngleDelta(circleX + distance, circleY); + final double polarY = MathUtils.getAngleDelta(circleX - distance, circleY); + + /* + * This is simply printing the result regularly without any issues. Simply, if a direction change, + * print -1 which will change the "way" we're running the prediction, otherwise print 1 which wont change it + */ + result = polarX < polarY ? 1 : -1; + } + + /* + * This is the check for the pitch variant of this. This has to be checked differently since one is + * a vertical value when the other one is an expression of a circle. They are not the same. + */ + else { + final float distance = current - previous; + + /* + * The check for pitch is the same we did before. It is much simpler since the rotation does not need + * to be expressed in the likes of a circle since it is clamped normally from the client. So the method is + * not as complex in comparison to the one we have for yaw. However, this should work fine as mentioned. + */ + result = distance > 0 ? 1 : -1; + } + + return result; + } + + /* + * This is an attempt to reverse the logistics of cinematic camera without having to run a full on prediction using + * mouse filters. Otherwise, we would need to run more heavy calculations which is not really production friendly. + * It may be more accurate but it is not really worth it if in the end of the day we're eating server performance. + */ + public static double getGrid(final List entry) { + /* + * We're creating the variables average min and max to start calculating the possibility of cinematic camera. + * Why does this work? Cinematic camera is essentially a slowly increasing slowdown (which is why cinematic camera + * becomes slower the more you use it) which in turn makes it so the min max and average are extremely close together. + */ + double average = 0.0; + double min = 0.0, max = 0.0; + + /* + * These are simple min max calculations done manually for the sake of simplicity. We're using the numbers 0.0 + * since we also want to account for the possibility of a negative number. If there are no negative numbers then + * there is absolutely no need for us to care about that number other than getting the max. + */ + for (final double number : entry) { + if (number < min) min = number; + if (number > max) max = number; + + /* + * Instead of having a sum variable we can use an average variable which we divide + * right after the loop is over. Smart programming trick if you want to use it. + */ + average += number; + } + + /* + * We're dividing the average by the length since this is the formula to getting the average. + * Specifically its (sum(n) / length(n)) = average(n) -- with n being the entry set we're analyzing. + */ + average /= entry.size(); + + /* + * This is going to estimate how close the average and the max were together with the possibility of a min + * variable which is going to represent a negative variable since the preset variable on min is 0.0. + */ + return (max - average) - min; + } + + public enum InverseType { + YAW, + PITCH + } +} diff --git a/src/main/java/dev/brighten/ac/utils/MathUtils.java b/src/main/java/dev/brighten/ac/utils/MathUtils.java index 67698ec..ffc313e 100644 --- a/src/main/java/dev/brighten/ac/utils/MathUtils.java +++ b/src/main/java/dev/brighten/ac/utils/MathUtils.java @@ -26,6 +26,13 @@ public class MathUtils { return playerMoved(from.toVector(), to.toVector()); } + public static float gcdSmall(float current, float previous) { + if(current < previous) return gcdSmall(Math.abs(previous), Math.abs(current)); + //The larger number has to be first. + return (Math.abs(previous) <= 0.001f) ? current : gcdSmall(previous, + current - (float)Math.floor(current / previous) * previous); + } + public static double getDistanceWithoutRoot(KLocation one, KLocation two) { double deltaX = one.x - two.x, deltaY = one.y - two.y, deltaZ = one.z - two.z; diff --git a/src/main/java/dev/brighten/ac/utils/timer/impl/TickTimer.java b/src/main/java/dev/brighten/ac/utils/timer/impl/TickTimer.java index b434fd5..db885fc 100644 --- a/src/main/java/dev/brighten/ac/utils/timer/impl/TickTimer.java +++ b/src/main/java/dev/brighten/ac/utils/timer/impl/TickTimer.java @@ -10,7 +10,7 @@ public class TickTimer implements Timer { public TickTimer(long defaultPassed) { this.defaultPassed = defaultPassed; - currentStamp = Anticheat.INSTANCE.getCurrentTick(); + currentStamp = Anticheat.INSTANCE.getKeepaliveProcessor().tick; } public TickTimer() { @@ -49,7 +49,7 @@ public class TickTimer implements Timer { @Override public long getPassed() { - return Anticheat.INSTANCE.getCurrentTick()- currentStamp; + return Anticheat.INSTANCE.getKeepaliveProcessor().tick - currentStamp; } @Override @@ -62,6 +62,6 @@ public class TickTimer implements Timer { if(getPassed() <= 1) resetStreak++; else resetStreak = 0; - currentStamp = Anticheat.INSTANCE.getCurrentTick(); + currentStamp = Anticheat.INSTANCE.getKeepaliveProcessor().tick; } }