From a04577b194fc9a2b2fb45d561efd8aa6e92963a7 Mon Sep 17 00:00:00 2001 From: Dawson <30784509+funkemunky@users.noreply.github.com> Date: Tue, 29 Nov 2022 10:00:44 -0500 Subject: [PATCH] lots of changes - Added inventory check type in API - Added Inventory (A) detection - Added Inventory (B) detection - Improved the flag rate and accuracy of Aim check - Added other bot check that flies around player to Killaura (Bot) to account for clients not doing a proper RayCast and opting to just turn on attack invisibles and mobs. - Added comments to Killaura (Trace) - Optimized Fly (A) detection and added comments - Fixed false positive caused by incorrect acceleration prediction in Fly (A). I used the current onGround when that is actually never a factor in vertical acceleration, only the product of what the client moves to. - Removed "optimization" in Fly (A) that basically just stopped prediction when client sends onGround and sets motionY to 0. Changed this behavior to it still do the acceleration subtraction 0.08 times 0.98 but run a collision check that will set the y to 0 if necessary; more closely replicates vanilla mechanics. - Optimized Horizontal check and fixing field name motionX to more appropriate motion name. - Optimized Velocity (B) by using current Horizontal optimizations and applying them to this check. - Moved logs command in AnticheatCommand class to its own LogsCommand class. Added other kinds of logs commands like /kauri logs paste to send it to pastebin and /kauri logs web to view logs on the website. - Fixed error on plugin shutdown caused by NPE. This was due to an order of operations issue with PlayerRegistry and PacketHandler - Added wrapper for PacketPlayInWindowClick, PacketPlayInClientCommand. - Added KLocation#getDirection() method as a shorthand to doing MathUtils.getDirection(KLocation field); - Moved Helper#angularDistance to MathUtils#angularDistance - Added CollisionBox#downcast() method as a shorthand method to not have to create a new List field every time I want to get the downcasted SimpleCollisionBox of any wrapped CollisionBox. --- .../dev/brighten/ac/api/check/CheckType.java | 1 + pom.xml | 6 + src/main/java/dev/brighten/ac/Anticheat.java | 25 +- .../ac/check/impl/combat/aim/Aim.java | 4 +- .../ac/check/impl/combat/killaura/KABot.java | 14 + .../check/impl/combat/killaura/KATrace.java | 23 +- .../check/impl/misc/inventory/InventoryA.java | 19 + .../check/impl/misc/inventory/InventoryB.java | 24 + .../ac/check/impl/movement/fly/FlyA.java | 57 +- .../check/impl/movement/speed/Horizontal.java | 88 ++- .../impl/movement/velocity/VelocityB.java | 286 ++++---- .../brighten/ac/command/AnticheatCommand.java | 87 +-- .../dev/brighten/ac/command/LogsCommand.java | 240 +++++++ .../java/dev/brighten/ac/data/APlayer.java | 28 + .../dev/brighten/ac/data/PlayerRegistry.java | 2 - .../ac/data/info/GeneralInformation.java | 6 +- .../ac/handler/EntityLocationHandler.java | 4 +- .../brighten/ac/handler/MovementHandler.java | 18 + .../brighten/ac/handler/PacketHandler.java | 29 + .../brighten/ac/listener/GeneralListener.java | 25 +- .../ac/packet/listener/PacketProcessor.java | 1 + .../ac/packet/wrapper/PacketConverter.java | 4 + .../ac/packet/wrapper/PacketType.java | 6 +- .../ac/packet/wrapper/impl/Processor_18.java | 20 + .../wrapper/in/WPacketPlayInWindowClick.java | 26 + .../out/WPacketPlayInClientCommand.java | 29 + .../java/dev/brighten/ac/utils/Helper.java | 614 +++++++++--------- .../java/dev/brighten/ac/utils/KLocation.java | 4 + .../java/dev/brighten/ac/utils/MathUtils.java | 6 + .../brighten/ac/utils/world/CollisionBox.java | 2 + .../world/types/ComplexCollisionBox.java | 10 + .../world/types/DynamicCollisionBox.java | 10 + .../ac/utils/world/types/NoCollisionBox.java | 6 + .../ac/utils/world/types/RayCollision.java | 6 + .../utils/world/types/SimpleCollisionBox.java | 6 + 35 files changed, 1154 insertions(+), 582 deletions(-) create mode 100644 src/main/java/dev/brighten/ac/check/impl/misc/inventory/InventoryA.java create mode 100644 src/main/java/dev/brighten/ac/check/impl/misc/inventory/InventoryB.java create mode 100644 src/main/java/dev/brighten/ac/command/LogsCommand.java create mode 100644 src/main/java/dev/brighten/ac/packet/wrapper/in/WPacketPlayInWindowClick.java create mode 100644 src/main/java/dev/brighten/ac/packet/wrapper/out/WPacketPlayInClientCommand.java diff --git a/API/src/main/java/dev/brighten/ac/api/check/CheckType.java b/API/src/main/java/dev/brighten/ac/api/check/CheckType.java index 16e2e77..a8cb470 100644 --- a/API/src/main/java/dev/brighten/ac/api/check/CheckType.java +++ b/API/src/main/java/dev/brighten/ac/api/check/CheckType.java @@ -9,6 +9,7 @@ public enum CheckType { CHAT, CRASH, EXPLOIT, + INVENTORY, INTERACT, ORDER, BADPACKETS diff --git a/pom.xml b/pom.xml index 23d31ef..1a420d6 100644 --- a/pom.xml +++ b/pom.xml @@ -86,6 +86,12 @@ + + dev.brighten.ac + API + 1.0 + compile + org.projectlombok lombok diff --git a/src/main/java/dev/brighten/ac/Anticheat.java b/src/main/java/dev/brighten/ac/Anticheat.java index 857c589..68db541 100644 --- a/src/main/java/dev/brighten/ac/Anticheat.java +++ b/src/main/java/dev/brighten/ac/Anticheat.java @@ -114,16 +114,18 @@ public class Anticheat extends LoaderPlugin { getAnticheatConfig().set("database.password", UUID.randomUUID().toString()); } + this.keepaliveProcessor = new KeepaliveProcessor(); + this.fakeTracker = new FakeEntityTracker(); this.checkManager = new CheckManager(); this.playerRegistry = new PlayerRegistry(); + HandlerAbstract.init(); + Bukkit.getOnlinePlayers().forEach(playerRegistry::generate); this.packetHandler = new PacketHandler(); logManager = new LoggerManager(); keepaliveProcessor.start(); - HandlerAbstract.init(); - logManager.init(); alog(Color.Green + "Loading WorldInfo system..."); @@ -136,19 +138,12 @@ public class Anticheat extends LoaderPlugin { e.printStackTrace(); } - fakeTracker = new FakeEntityTracker(); - Bukkit.getOnlinePlayers().forEach(HandlerAbstract.getHandler()::add); } public void onDisable() { scheduler.shutdown(); commandManager.unregisterCommands(); - // Unregistering packet listeners for players - HandlerAbstract.getHandler().shutdown(); - HandlerList.unregisterAll(getPluginInstance()); - packetProcessor.shutdown(); - packetProcessor = null; checkManager.getCheckClasses().clear(); Check.alertsEnabled.clear(); Check.debugInstances.clear(); @@ -158,9 +153,6 @@ public class Anticheat extends LoaderPlugin { ProtocolAPI.INSTANCE = null; tps = null; - fakeTracker.despawnAll(); - fakeTracker = null; - logManager.shutDown(); Bukkit.getScheduler().cancelTasks(getPluginInstance()); @@ -176,6 +168,15 @@ public class Anticheat extends LoaderPlugin { throw new RuntimeException(e); } + fakeTracker.despawnAll(); + fakeTracker = null; + + // Unregistering packet listeners for players + HandlerAbstract.getHandler().shutdown(); + HandlerList.unregisterAll(getPluginInstance()); + packetProcessor.shutdown(); + packetProcessor = null; + AnticheatAPI.INSTANCE = null; onTickEnd.clear(); diff --git a/src/main/java/dev/brighten/ac/check/impl/combat/aim/Aim.java b/src/main/java/dev/brighten/ac/check/impl/combat/aim/Aim.java index 96bbb75..cc00360 100644 --- a/src/main/java/dev/brighten/ac/check/impl/combat/aim/Aim.java +++ b/src/main/java/dev/brighten/ac/check/impl/combat/aim/Aim.java @@ -49,8 +49,6 @@ public class Aim extends Check { return; } - boolean increasing = deltaYaw > deltaX || deltaPitch > deltaY; - boolean flagged = false; if(player.getMovement().getPitchGCD() < 0.007 && lastGrid.isPassed() && !player.getMovement().isCinematic() @@ -69,7 +67,7 @@ public class Aim extends Check { /* * 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. + * 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) { /* diff --git a/src/main/java/dev/brighten/ac/check/impl/combat/killaura/KABot.java b/src/main/java/dev/brighten/ac/check/impl/combat/killaura/KABot.java index bc25c79..84fe950 100644 --- a/src/main/java/dev/brighten/ac/check/impl/combat/killaura/KABot.java +++ b/src/main/java/dev/brighten/ac/check/impl/combat/killaura/KABot.java @@ -5,6 +5,7 @@ import dev.brighten.ac.check.Check; import dev.brighten.ac.check.CheckData; import dev.brighten.ac.check.WAction; import dev.brighten.ac.data.APlayer; +import dev.brighten.ac.packet.wrapper.in.WPacketPlayInArmAnimation; import dev.brighten.ac.packet.wrapper.in.WPacketPlayInUseEntity; import lombok.val; @@ -16,6 +17,12 @@ public class KABot extends Check { } private int buffer = 0; + private float buffer2; + + WAction arm = packet -> { + // We want to go ahead and lower the buffer every time they miss the bot to help prevent false positives + if(buffer2 > 0) buffer2-= 0.25f; + }; WAction packet = packet -> { val optional = player.getEntityLocationHandler().getFakeMob(packet.getEntityId()); @@ -25,5 +32,12 @@ public class KABot extends Check { flag("Attacked player without attacking bot!"); } } else buffer = 0; + + if(player.getMob().getEntityId() == packet.getEntityId()) { + if(++buffer2 > 3) { + buffer = 2; + flag("Player attacked bot"); + } + } else buffer2 = 0; }; } diff --git a/src/main/java/dev/brighten/ac/check/impl/combat/killaura/KATrace.java b/src/main/java/dev/brighten/ac/check/impl/combat/killaura/KATrace.java index 0eb0c08..75c7833 100644 --- a/src/main/java/dev/brighten/ac/check/impl/combat/killaura/KATrace.java +++ b/src/main/java/dev/brighten/ac/check/impl/combat/killaura/KATrace.java @@ -8,13 +8,18 @@ import dev.brighten.ac.data.APlayer; import dev.brighten.ac.packet.ProtocolVersion; import dev.brighten.ac.packet.wrapper.in.WPacketPlayInUseEntity; import dev.brighten.ac.utils.KLocation; -import dev.brighten.ac.utils.MathUtils; import dev.brighten.ac.utils.world.CollisionBox; import dev.brighten.ac.utils.world.EntityData; import dev.brighten.ac.utils.world.types.RayCollision; import dev.brighten.ac.utils.world.types.SimpleCollisionBox; import org.bukkit.util.Vector; +/** + * @author funkemunky + * @since 12/31/2020 + * This check is designed to detect an attack through solid blocks, which would be impossible under normal + * circumstances. + */ @CheckData(name = "KillAura (Trace)", checkId = "katrace", type = CheckType.KILLAURA) public class KATrace extends Check { @@ -22,6 +27,7 @@ public class KATrace extends Check { public KATrace(APlayer player) { super(player); + // We're caching the player's sneak height here, so we don't have to do it every time. sneakY = player.getPlayerVersion().isBelow(ProtocolVersion.V1_14) ? 1.27f : 1.54f; } @@ -32,33 +38,42 @@ public class KATrace extends Check { || packet.getAction() != WPacketPlayInUseEntity.EnumEntityUseAction.ATTACK) return; + // If the player isn't looking at the target, then a raytrace check wouldn't work. if(player.getMovement().getLookingAtBoxes().size() == 0) { debug("No boxes to look at!"); buffer = 0; return; } - SimpleCollisionBox targetBox = (SimpleCollisionBox) EntityData.getEntityBox(player.getInfo().getTarget().getLocation(), + // Getting the target's bounding box + SimpleCollisionBox targetBox = (SimpleCollisionBox) EntityData.getEntityBox(player.getInfo().getTarget() + .getLocation(), player.getInfo().target); if(targetBox == null) return; final KLocation origin = player.getMovement().getTo().getLoc().clone(); + // Setting the player's eye height based on their sneak status origin.y+= player.getInfo().isSneaking() ? sneakY : 1.62f; final Vector originVec = origin.toVector(); - RayCollision collision = new RayCollision(originVec, MathUtils.getDirection(origin)); + // Setting a trace based on their view direction + RayCollision collision = new RayCollision(originVec, origin.getDirection()); Vector targetPoint = collision.collisionPoint(targetBox); //If the ray isn't collided, we might as well not run this check. Just a simple boxes on array check if(targetPoint == null) return; + // The distance bteween the player's eye and the intersect point of the ray and the target's bounding box. + // We don't do the square root to save on performance. double dist = originVec.distanceSquared(targetPoint); boolean rayCollidedOnBlock = false; + // Grabbing the boxes found on the ray trace. This is already grabbed in MovementProcessor so we can use + // the result from there in this check to save on compute time. synchronized (player.getMovement().getLookingAtBoxes()) { for (CollisionBox lookingAtBox : player.getMovement().getLookingAtBoxes()) { if((lookingAtBox instanceof SimpleCollisionBox)) { @@ -67,6 +82,7 @@ public class KATrace extends Check { || box.maxX % 1 != 0 || box.maxY % 1 != 0 || box.maxZ % 1 != 0) continue; + // We want to shrink the box slightly since there is a bit of a margin of error in the ray trace. Vector point = collision.collisionPoint(box.copy().shrink(0.005f, 0.005f, 0.005f)); if (point != null && originVec.distanceSquared(point) < dist - 0.2) { @@ -78,6 +94,7 @@ public class KATrace extends Check { } if(rayCollidedOnBlock) { + // The buffer is here to smooth out false positives. if(++buffer > 2) { flag("Attacker hit through block! [b=%s s=%s]", buffer, player.getMovement().getLookingAtBoxes().size()); diff --git a/src/main/java/dev/brighten/ac/check/impl/misc/inventory/InventoryA.java b/src/main/java/dev/brighten/ac/check/impl/misc/inventory/InventoryA.java new file mode 100644 index 0000000..a4803c0 --- /dev/null +++ b/src/main/java/dev/brighten/ac/check/impl/misc/inventory/InventoryA.java @@ -0,0 +1,19 @@ +package dev.brighten.ac.check.impl.misc.inventory; + +import dev.brighten.ac.api.check.CheckType; +import dev.brighten.ac.check.Check; +import dev.brighten.ac.check.CheckData; +import dev.brighten.ac.data.APlayer; + +/** + * Check runs inside {@link dev.brighten.ac.check.impl.movement.speed.Horizontal} + */ +@CheckData(name = "Inventory (A)", checkId = "inventoryA", type = CheckType.INVENTORY) +public class InventoryA extends Check { + + public InventoryA(APlayer player) { + super(player); + } + + public int buffer; +} diff --git a/src/main/java/dev/brighten/ac/check/impl/misc/inventory/InventoryB.java b/src/main/java/dev/brighten/ac/check/impl/misc/inventory/InventoryB.java new file mode 100644 index 0000000..fbb34b7 --- /dev/null +++ b/src/main/java/dev/brighten/ac/check/impl/misc/inventory/InventoryB.java @@ -0,0 +1,24 @@ +package dev.brighten.ac.check.impl.misc.inventory; + +import dev.brighten.ac.api.check.CheckType; +import dev.brighten.ac.check.Check; +import dev.brighten.ac.check.CheckData; +import dev.brighten.ac.check.WAction; +import dev.brighten.ac.data.APlayer; +import dev.brighten.ac.packet.wrapper.in.WPacketPlayInWindowClick; + +@CheckData(name = "Inventory (B)", checkId = "inventoryB", type = CheckType.INVENTORY) +public class InventoryB extends Check { + + public InventoryB(APlayer player) { + super(player); + } + + WAction windowClick = packet -> { + if(!player.getInfo().isInventoryOpen()) { + flag("Inventory not open"); + } + debug("inv=%s", player.getInfo().isInventoryOpen()); + }; + +} diff --git a/src/main/java/dev/brighten/ac/check/impl/movement/fly/FlyA.java b/src/main/java/dev/brighten/ac/check/impl/movement/fly/FlyA.java index 551d8a4..9bfe632 100644 --- a/src/main/java/dev/brighten/ac/check/impl/movement/fly/FlyA.java +++ b/src/main/java/dev/brighten/ac/check/impl/movement/fly/FlyA.java @@ -36,10 +36,30 @@ public class FlyA extends Check { return; } + // This stuff will false flag the detection and cause a buffer decrease, so we're just going to prevent + // the check from processing to save resources. + if(player.getInfo().isGeneralCancel() + || player.getMovement().getTeleportsToConfirm() > 0 + || player.getInfo().isOnLadder() + || player.getInfo().climbTimer.isNotPassed(2) + || player.getBlockInfo().inWeb + || player.getBlockInfo().inScaffolding + || player.getInfo().getLastLiquid().isNotPassed(2) + || player.getBlockInfo().fenceBelow + || !player.getInfo().worldLoaded + || player.getBlockInfo().onHalfBlock + || player.getInfo().getVelocity().isNotPassed(1) + || player.getBlockInfo().onSlime) { + if(buffer > 0) buffer-= 0.25f; + return; + } + boolean onGround = player.getMovement().getTo().isOnGround() && player.getBlockInfo().blocksBelow, fromGround = player.getMovement().getFrom().isOnGround(); - double lDeltaY = fromGround ? 0 : player.getMovement().getLDeltaY(); - double predicted = onGround ? lDeltaY : (lDeltaY - 0.08) * mult; + double lDeltaY = player.getMovement().getLDeltaY(); + + // Initial acceleration prediction the vanilla client does + double predicted = (lDeltaY - 0.08) * mult; if(fromGround && !onGround && player.getMovement().getDeltaY() > 0) { predicted = MovementUtils.getJumpHeight(player); @@ -50,6 +70,9 @@ public class FlyA extends Check { boolean willBeWeirdNext = didNextPrediction; didNextPrediction = false; + // Since the player skipped a flying packet, the client likely didn't send a small position update + // This is to go ahead and account for that just in case the >60ms delta is caused by a < 9.0E-4 small movement + // on all axis. See net.minecraft.client.entity.EntityPlayerSP#onUpdateWalkingPlayer method if(lastPos.isPassed(60L)) { double toCheck = (predicted - 0.08) * mult; @@ -60,6 +83,7 @@ public class FlyA extends Check { } } + // Vanilla wrapping the deltaY to 0 if it's less than a certain amount. if(player.getPlayerVersion().isBelow(ProtocolVersion.V1_9)) { if(Math.abs(predicted) < 0.005) predicted = 0; @@ -68,6 +92,8 @@ public class FlyA extends Check { debug("Setting y to 0"); } + // Vanilla collision algorithm to correct any false positives related to modified deltaY related to ground + // collision. if(player.getBlockInfo().blocksBelow || player.getInfo().isNearGround()) { List list = Helper.getCollisions(player, player.getMovement().getFrom().getBox().copy().addCoord(player.getMovement().getDeltaX(), predicted, @@ -90,20 +116,13 @@ public class FlyA extends Check { double deltaPredict = MathUtils.getDelta(player.getMovement().getDeltaY(), predicted); - if(!player.getInfo().isGeneralCancel() - && player.getMovement().getTeleportsToConfirm() == 0 - && !player.getInfo().isOnLadder() - && player.getInfo().climbTimer.isPassed(2) - && !player.getBlockInfo().inWeb - && !willBeWeirdNext - && !player.getBlockInfo().inScaffolding - && player.getInfo().getLastLiquid().isPassed(2) - && !player.getBlockInfo().fenceBelow - && player.getInfo().worldLoaded - && !player.getBlockInfo().onHalfBlock - && player.getInfo().getVelocity().isPassed(1) - && !player.getBlockInfo().onSlime - && deltaPredict > (player.getInfo().getClientAirTicks() < 3 ? 0.017 : 0.001)) { + // We want it to be at 0.005 since that is the maximum variance from loss of precision + // We also don't really want to flag if there was a skip in flying related to < 9.0E-4 movement. + if(!willBeWeirdNext + && deltaPredict > 0.005) { + // This slight buffer is to account for anything this check may have not accounted for + // It is not a permanent fix. However, Java Edition is quite a fickle game to work with; it's quite + // difficult to reliably check that vanilla behavior is vanilla behavior without weird outliers. if(++buffer > 1) { buffer = 1; flag("dY=%.3f p=%.3f dx=%.3f", player.getMovement().getDeltaY(), predicted, @@ -112,8 +131,10 @@ public class FlyA extends Check { } } else buffer-= buffer > 0 ? 0.25f : 0; - debug("dY=%.3f p=%.3f dx=%.3f b=%s velocity=%s", player.getMovement().getDeltaY(), predicted, - player.getMovement().getDeltaXZ(), buffer, player.getInfo().getVelocity().getPassed()); + debug("dY=%.3f p=%.3f dx=%.3f b=%s velocity=%s g=%s bbelow=%s ng=%s", + player.getMovement().getDeltaY(), predicted, player.getMovement().getDeltaXZ(), buffer, + player.getInfo().getVelocity().getPassed(), packet.isOnGround(), player.getBlockInfo().blocksBelow, + player.getInfo().isNearGround()); lastPos.reset(); }; diff --git a/src/main/java/dev/brighten/ac/check/impl/movement/speed/Horizontal.java b/src/main/java/dev/brighten/ac/check/impl/movement/speed/Horizontal.java index d19e164..9b607c0 100644 --- a/src/main/java/dev/brighten/ac/check/impl/movement/speed/Horizontal.java +++ b/src/main/java/dev/brighten/ac/check/impl/movement/speed/Horizontal.java @@ -4,6 +4,7 @@ import dev.brighten.ac.api.check.CheckType; import dev.brighten.ac.check.Check; import dev.brighten.ac.check.CheckData; import dev.brighten.ac.check.WAction; +import dev.brighten.ac.check.impl.misc.inventory.InventoryA; import dev.brighten.ac.data.APlayer; import dev.brighten.ac.packet.ProtocolVersion; import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying; @@ -21,6 +22,7 @@ import org.bukkit.util.Vector; import java.util.ArrayList; import java.util.List; +import java.util.Optional; @CheckData(name = "Horizontal", checkId = "horizontala", type = CheckType.MOVEMENT, experimental = true) public class Horizontal extends Check { @@ -31,7 +33,7 @@ public class Horizontal extends Check { private int lastFlying; private KLocation previousFrom; - private Vector motionX = new Vector(0, 0, 0); + private Vector motion = new Vector(0, 0, 0); private static final boolean[] TRUE_FALSE = new boolean[]{true, false}; public double strafe, forward; @@ -44,6 +46,12 @@ public class Horizontal extends Check { check: { + if(!packet.isMoved() || (player.getMovement().getDeltaXZ() == 0)) { + forward = strafe = 0; + } + + Optional inventoryA = find(InventoryA.class); + if (!packet.isMoved() || player.getMovement().getMoveTicks() == 0 || player.getMovement().getLastTeleport().isNotPassed(1) @@ -54,8 +62,12 @@ public class Horizontal extends Check { || player.getMovement().getTo().getLoc() .distanceSquared(player.getMovement().getFrom().getLoc()) > 2500 || player.getInfo().lastLiquid.isNotPassed(2)) { - motionX = new Vector(player.getMovement().getDeltaX(), player.getMovement().getDeltaY(), + motion = new Vector(player.getMovement().getDeltaX(), player.getMovement().getDeltaY(), player.getMovement().getDeltaZ()); + inventoryA.ifPresent(check -> { + if(check.buffer > 0) + check.buffer--; + }); break check; } @@ -70,6 +82,9 @@ public class Horizontal extends Check { double precision = getPrecision(); TagsBuilder tags = null; + val speed = player.getPotionHandler().getEffectByType(PotionEffectType.SPEED); + val slow = player.getPotionHandler().getEffectByType(PotionEffectType.SLOW); + for (Iteration it : iterations) { TagsBuilder tagsBuilder = new TagsBuilder(); @@ -100,9 +115,17 @@ public class Horizontal extends Check { double aiMoveSpeed = player.getBukkitPlayer().getWalkSpeed() / 2; float drag = 0.91f; - double lmotionX = motionX.getX(), - lmotionY = motionX.getY(), - lmotionZ = motionX.getZ(); + double lmotionX = motion.getX(), + lmotionY = motion.getY(), + lmotionZ = motion.getZ(); + + double totalMotion = Math.abs(lmotionX) + Math.abs(lmotionY) + Math.abs(lmotionZ); + + if(totalMotion > 30) { + motion = new Vector(player.getMovement().getDeltaX(), player.getMovement().getDeltaY(), + player.getMovement().getDeltaZ()); + return; + } lmotionY -= 0.08; lmotionY *= 0.98f; @@ -152,17 +175,12 @@ public class Horizontal extends Check { tagsBuilder.addTag("sprinting"); } - if (player.getPotionHandler().hasPotionEffect(PotionEffectType.SPEED)) { - aiMoveSpeed += (player.getPotionHandler().getEffectByType(PotionEffectType.SPEED) - .map(pe -> pe.getAmplifier() + 1)).orElse(0) - * 0.20000000298023224D * aiMoveSpeed; - + if (speed.isPresent()) { + aiMoveSpeed += (speed.get().getAmplifier() + 1) * (double) 0.20000000298023224D * aiMoveSpeed; tagsBuilder.addTag("speedPotion"); } - if (player.getPotionHandler().hasPotionEffect(PotionEffectType.SLOW)) { - aiMoveSpeed += (player.getPotionHandler().getEffectByType(PotionEffectType.SLOW) - .map(pe -> pe.getAmplifier() + 1)).orElse(0) - * -0.15000000596046448D * aiMoveSpeed; + if (slow.isPresent()) { + aiMoveSpeed += (slow.get().getAmplifier() + 1) * (double) -0.15000000596046448D * aiMoveSpeed; tagsBuilder.addTag("slowPotion"); } @@ -439,17 +457,11 @@ public class Horizontal extends Check { double delta = (diffX * diffX) + (diffZ * diffZ); double deltaAll = delta + (diffY * diffY); - if(forward > 0 && strafe == 0 && !it.attack && !it.sneaking && !it.using && it.sprinting - && !it.edge && !it.jumped) { - debug("Shit: tags=[%s] diffX=%.6f diffZ=%.6f oy=%.3f ly=%.3f", tagsBuilder.build(), diffX, diffZ, - originalY, lmotionY); - } - if (delta < smallestDeltaXZ) { - smallDelta = deltaAll; + //smallDelta = deltaAll; smallestDeltaXZ = delta; predictedMotionX = lmotionX; - predictedMotionY = lmotionY; + //predictedMotionY = lmotionY; predictedMotionZ = lmotionZ; tags = tagsBuilder; @@ -459,9 +471,9 @@ public class Horizontal extends Check { this.forward = it.f * 0.98f; if (precision < 1E-11) - motionX = new Vector(lmotionX, lmotionY, lmotionZ); + motion = new Vector(lmotionX, lmotionY, lmotionZ); else - motionX = new Vector(player.getMovement().getDeltaX(), player.getMovement().getDeltaY(), player.getMovement().getDeltaZ()); + motion = new Vector(player.getMovement().getDeltaX(), player.getMovement().getDeltaY(), player.getMovement().getDeltaZ()); if (player.getInfo().getLastCancel().isPassed(2)) player.getInfo() @@ -476,10 +488,24 @@ public class Horizontal extends Check { } } } + + // Inventory (A) check + inventoryA.ifPresent(check -> { + + if((strafe != 0 || forward != 0) && player.getInfo().isInventoryOpen()) { + if(check.buffer++ > 6) { + check.buffer = Math.min(8, check.buffer); + check.flag("s=%.2f f=%.2f", strafe, forward); + } + } else if(check.buffer > 0) check.buffer--; + + check.debug("buffer=%d inv=%s s=%.2f f=%.2f", check.buffer, + player.getInfo().isInventoryOpen(), strafe, forward); + }); iterations.clear(); if (!found) { - motionX = new Vector(player.getMovement().getDeltaX(), player.getMovement().getDeltaY(), player.getMovement().getDeltaZ()); + motion = new Vector(player.getMovement().getDeltaX(), player.getMovement().getDeltaY(), player.getMovement().getDeltaZ()); } final String builtTags = tags == null ? "null" : tags.build(); @@ -489,17 +515,15 @@ public class Horizontal extends Check { && player.getMovement().getDeltaXZ() > 0.1) { if ((buffer += smallestDeltaXZ > 58E-5 ? 1 : 0.5) > 1) { buffer = Math.min(3.5f, buffer); //Ensuring we don't have a run-away buffer - flag("smallest=%s b=%.1f to=%s dxz=%.2f tags=[%s]", smallestDeltaXZ, buffer, - player.getMovement().getTo().getLoc(), player.getMovement().getDeltaXZ(), builtTags); + flag("smallest=%.7f b=%.1f dxz=%.2f tags=[%s]", smallestDeltaXZ, buffer, + player.getMovement().getDeltaXZ(), builtTags); cancel(); } else debug("bad movement"); } else if (buffer > 0) buffer -= 0.05f; - /*debug("(%s): py=%.5f dy=%.5f pm=%.5f dxz=%.5f skip=%s b=%.1f tags=[%s]", - precision, predictedMotionY, player.getMovement().getDeltaY(), pmotion, - player.getMovement().getDeltaXZ(), maybeSkippedPos, buffer, builtTags);*/ - debug("x=%s z=%s tags=[%s]", predictedMotionX, predictedMotionZ, builtTags); + debug("[%.1f] smallest=%.7f dxz=%.2f tags=[%s]", buffer, smallestDeltaXZ, + player.getMovement().getDeltaXZ(), builtTags); } if (ProtocolVersion.getGameVersion().isBelow(ProtocolVersion.V1_9)) { @@ -586,7 +610,7 @@ public class Horizontal extends Check { } private static boolean[] getJumpingIteration(boolean onGround) { - return onGround ? new boolean[]{true, false} : new boolean[]{false}; + return new boolean[]{true, false}; } private static final float[] SIN_TABLE_FAST = new float[4096], SIN_TABLE_FAST_NEW = new float[4096]; diff --git a/src/main/java/dev/brighten/ac/check/impl/movement/velocity/VelocityB.java b/src/main/java/dev/brighten/ac/check/impl/movement/velocity/VelocityB.java index 16145b6..0efbe9f 100644 --- a/src/main/java/dev/brighten/ac/check/impl/movement/velocity/VelocityB.java +++ b/src/main/java/dev/brighten/ac/check/impl/movement/velocity/VelocityB.java @@ -12,11 +12,15 @@ import dev.brighten.ac.utils.MathHelper; import dev.brighten.ac.utils.math.IntVector; import dev.brighten.ac.utils.timer.Timer; import dev.brighten.ac.utils.timer.impl.TickTimer; +import lombok.AllArgsConstructor; import lombok.val; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_8_R3.util.CraftMagicNumbers; import org.bukkit.potion.PotionEffectType; +import java.util.ArrayList; +import java.util.List; + @CheckData(name = "Velocity (Horizontal)", checkId = "velocityb", type = CheckType.MOVEMENT) public class VelocityB extends Check { private Timer lastVelocity = new TickTimer(); @@ -37,7 +41,6 @@ public class VelocityB extends Check { } private double pvX, pvZ; - private boolean useEntity, sprint; private int ticks; private double buffer; private float friction; @@ -74,155 +77,128 @@ public class VelocityB extends Check { double pmotionx = 0, pmotionz = 0; boolean onGround = player.getMovement().getFrom().isOnGround(); - loop: - { - for (int f = -1; f < 2; f++) { - for (int s = -1; s < 2; s++) { - for (boolean sprinting : TRUE_FALSE) { - for (int fastMath = 0; fastMath <= 2; fastMath++) { - for (boolean attack : TRUE_FALSE) { - for (boolean using : TRUE_FALSE) { - for (boolean sneaking : TRUE_FALSE) { - for (boolean jumped : TRUE_FALSE) { + val speed = player.getPotionHandler().getEffectByType(PotionEffectType.SPEED); + val slow = player.getPotionHandler().getEffectByType(PotionEffectType.SLOW); - float forward = f, strafe = s; + for (Iteration iteration : iterations) { + float forward = iteration.f, strafe = iteration.s; - if (sprinting && forward <= 0) { - continue; - } + if (iteration.sneaking) { + forward *= 0.3; + strafe *= 0.3; + } - if (sneaking) { - forward *= 0.3; - strafe *= 0.3; - } + float friction = CraftMagicNumbers.getBlock(underMaterial).frictionFactor; - float friction = CraftMagicNumbers.getBlock(underMaterial).frictionFactor; + if (iteration.using) { + forward *= 0.2; + strafe *= 0.2; + } - if (using) { - forward *= 0.2; - strafe *= 0.2; - } + //Multiplying by 0.98 like in client + forward *= 0.9800000190734863F; + strafe *= 0.9800000190734863F; - //Multiplying by 0.98 like in client - forward *= 0.9800000190734863F; - strafe *= 0.9800000190734863F; + double aiMoveSpeed = player.getBukkitPlayer().getWalkSpeed() / 2; - double aiMoveSpeed = player.getBukkitPlayer().getWalkSpeed() / 2; + float drag = 0.91f; + double lmotionX = pvX, + lmotionZ = pvZ; - float drag = 0.91f; - double lmotionX = pvX, - lmotionZ = pvZ; + //Running multiplication done after previous prediction + if (player.getPlayerVersion().isOrAbove(ProtocolVersion.V1_9)) { + if (Math.abs(lmotionX) < 0.003) + lmotionX = 0; + if (Math.abs(lmotionZ) < 0.003) + lmotionZ = 0; + } else { + if (Math.abs(lmotionX) < 0.005) + lmotionX = 0; + if (Math.abs(lmotionZ) < 0.005) + lmotionZ = 0; + } - //lmotionX *= (lastLastClientGround ? lfriction : 1) * 0.9100000262260437D; - //lmotionZ *= (lastLastClientGround ? lfriction : 1) * 0.9100000262260437D; + //Less than 0.05 + if (((lmotionX * lmotionX) + (lmotionZ * lmotionZ)) < 0.0025 && player.getMovement().getDeltaXZ() < 0.2) { + break check; + } + // Attack slowdown + if (iteration.attack) { + lmotionX *= 0.6; + lmotionZ *= 0.6; + } - //Running multiplication done after previous prediction - if (player.getPlayerVersion().isOrAbove(ProtocolVersion.V1_9)) { - if (Math.abs(lmotionX) < 0.003) - lmotionX = 0; - if (Math.abs(lmotionZ) < 0.003) - lmotionZ = 0; - } else { - if (Math.abs(lmotionX) < 0.005) - lmotionX = 0; - if (Math.abs(lmotionZ) < 0.005) - lmotionZ = 0; - } + if (iteration.sprinting) + aiMoveSpeed += aiMoveSpeed * 0.30000001192092896D; - //Less than 0.05 - if (((lmotionX * lmotionX) + (lmotionZ * lmotionZ)) < 0.0025 && player.getMovement().getDeltaXZ() < 0.2) { - break check; - } - // Attack slowdown - if (attack) { - lmotionX *= 0.6; - lmotionZ *= 0.6; - } + if (speed.isPresent()) + aiMoveSpeed += (speed.get().getAmplifier() + 1) * (double) 0.20000000298023224D * aiMoveSpeed; + if (slow.isPresent()) + aiMoveSpeed += (slow.get().getAmplifier() + 1) * (double) -0.15000000596046448D * aiMoveSpeed; - if (sprinting) - aiMoveSpeed += aiMoveSpeed * 0.30000001192092896D; + float f5; + if (onGround) { + drag *= friction; - if (player.getPotionHandler().hasPotionEffect(PotionEffectType.SPEED)) - aiMoveSpeed += (player.getPotionHandler().getEffectByType(PotionEffectType.SPEED) - .get() - .getAmplifier() + 1) * (double) 0.20000000298023224D * aiMoveSpeed; - if (player.getPotionHandler().hasPotionEffect(PotionEffectType.SLOW)) - aiMoveSpeed += (player.getPotionHandler().getEffectByType(PotionEffectType.SLOW) - .get() - .getAmplifier() + 1) * (double) -0.15000000596046448D * aiMoveSpeed; + f5 = (float) (aiMoveSpeed * (0.16277136F / (drag * drag * drag))); - float f5; - if (onGround) { - drag *= friction; - - f5 = (float) (aiMoveSpeed * (0.16277136F / (drag * drag * drag))); - - if (sprinting && jumped) { - float rot = player.getMovement().getTo().getLoc().yaw * 0.017453292F; - lmotionX -= sin(fastMath, rot) * 0.2F; - lmotionZ += cos(fastMath, rot) * 0.2F; - } - - } else f5 = sprinting ? 0.025999999F : 0.02f; - - if (player.getPlayerVersion().isOrAbove(ProtocolVersion.V1_9)) { - double keyedMotion = forward * forward + strafe * strafe; - - if (keyedMotion >= 1.0E-4F) { - keyedMotion = f5 / Math.max(1.0, Math.sqrt(keyedMotion)); - forward *= keyedMotion; - strafe *= keyedMotion; - - final float yawSin = sin(fastMath, - player.getMovement().getTo().getLoc().yaw * (float) Math.PI / 180.F), - yawCos = cos(fastMath, - player.getMovement().getTo().getLoc().yaw * (float) Math.PI / 180.F); - - lmotionX += (strafe * yawCos - forward * yawSin); - lmotionZ += (forward * yawCos + strafe * yawSin); - } - } else { - float keyedMotion = forward * forward + strafe * strafe; - - if (keyedMotion >= 1.0E-4F) { - keyedMotion = f5 / Math.max(1.0f, MathHelper.sqrt_float(keyedMotion)); - forward *= keyedMotion; - strafe *= keyedMotion; - - final float yawSin = sin(fastMath, - player.getMovement().getTo().getLoc().yaw * (float) Math.PI / 180.F), - yawCos = cos(fastMath, - player.getMovement().getTo().getLoc().yaw * (float) Math.PI / 180.F); - - lmotionX += (strafe * yawCos - forward * yawSin); - lmotionZ += (forward * yawCos + strafe * yawSin); - } - } - double diffX = player.getMovement().getDeltaX() - lmotionX, - diffZ = player.getMovement().getDeltaZ() - lmotionZ; - double delta = (diffX * diffX) + (diffZ * diffZ); - - if (delta < smallestDelta) { - smallestDelta = delta; - pmotionx = lmotionX; - pmotionz = lmotionZ; - this.friction = friction; - - if (delta < 4E-17) { - this.strafe = s * 0.98f; - this.forward = f * 0.98f; - - break loop; - } - } - } - } - } - } - } - } + if (iteration.sprinting && iteration.jumped) { + float rot = player.getMovement().getTo().getLoc().yaw * 0.017453292F; + lmotionX -= sin(iteration.fastMath, rot) * 0.2F; + lmotionZ += cos(iteration.fastMath, rot) * 0.2F; } + } else f5 = iteration.sprinting ? 0.025999999F : 0.02f; + + if (player.getPlayerVersion().isOrAbove(ProtocolVersion.V1_9)) { + double keyedMotion = forward * forward + strafe * strafe; + + if (keyedMotion >= 1.0E-4F) { + keyedMotion = f5 / Math.max(1.0, Math.sqrt(keyedMotion)); + forward *= keyedMotion; + strafe *= keyedMotion; + + final float yawSin = sin(iteration.fastMath, + player.getMovement().getTo().getLoc().yaw * (float) Math.PI / 180.F), + yawCos = cos(iteration.fastMath, + player.getMovement().getTo().getLoc().yaw * (float) Math.PI / 180.F); + + lmotionX += (strafe * yawCos - forward * yawSin); + lmotionZ += (forward * yawCos + strafe * yawSin); + } + } else { + float keyedMotion = forward * forward + strafe * strafe; + + if (keyedMotion >= 1.0E-4F) { + keyedMotion = f5 / Math.max(1.0f, MathHelper.sqrt_float(keyedMotion)); + forward *= keyedMotion; + strafe *= keyedMotion; + + final float yawSin = sin(iteration.fastMath, + player.getMovement().getTo().getLoc().yaw * (float) Math.PI / 180.F), + yawCos = cos(iteration.fastMath, + player.getMovement().getTo().getLoc().yaw * (float) Math.PI / 180.F); + + lmotionX += (strafe * yawCos - forward * yawSin); + lmotionZ += (forward * yawCos + strafe * yawSin); + } + } + double diffX = player.getMovement().getDeltaX() - lmotionX, + diffZ = player.getMovement().getDeltaZ() - lmotionZ; + double delta = (diffX * diffX) + (diffZ * diffZ); + + if (delta < smallestDelta) { + smallestDelta = delta; + pmotionx = lmotionX; + pmotionz = lmotionZ; + this.friction = friction; + + if (delta < 4E-17) { + this.strafe = iteration.s * 0.98f; + this.forward = iteration.f * 0.98f; + + break; + } } } @@ -250,6 +226,48 @@ public class VelocityB extends Check { previousFrom = player.getMovement().getFrom().getLoc().clone(); }; + /* + for (int f = -1; f < 2; f++) { + for (int s = -1; s < 2; s++) { + for (boolean sprinting : TRUE_FALSE) { + for (int fastMath = 0; fastMath <= 2; fastMath++) { + for (boolean attack : TRUE_FALSE) { + for (boolean using : TRUE_FALSE) { + for (boolean sneaking : TRUE_FALSE) { + for (boolean jumped : TRUE_FALSE) { + */ + + @AllArgsConstructor + private static class Iteration { + final int f, s, fastMath; + final boolean sprinting, attack, using, sneaking, jumped; + } + + private static final List iterations = new ArrayList<>(); + + static { + for (int f = -1; f < 2; f++) { + for (int s = -1; s < 2; s++) { + for (boolean sprinting : TRUE_FALSE) { + for (int fastMath = 0; fastMath <= 2; fastMath++) { + for (boolean attack : TRUE_FALSE) { + for (boolean using : TRUE_FALSE) { + for (boolean sneaking : TRUE_FALSE) { + for (boolean jumped : TRUE_FALSE) { + if(sprinting && f <= 0) continue; + if(jumped && !sprinting) continue; + iterations.add(new Iteration(f, s, fastMath, sprinting, + attack, using, sneaking, jumped)); + } + } + } + } + } + } + } + } + } + private static final float[] SIN_TABLE_FAST = new float[4096], SIN_TABLE_FAST_NEW = new float[4096]; private static final float[] SIN_TABLE = new float[65536]; private static final float radToIndex = roundToFloat(651.8986469044033D); diff --git a/src/main/java/dev/brighten/ac/command/AnticheatCommand.java b/src/main/java/dev/brighten/ac/command/AnticheatCommand.java index fe05389..25b864f 100644 --- a/src/main/java/dev/brighten/ac/command/AnticheatCommand.java +++ b/src/main/java/dev/brighten/ac/command/AnticheatCommand.java @@ -2,20 +2,15 @@ package dev.brighten.ac.command; import co.aikar.commands.*; import co.aikar.commands.annotation.*; -import co.aikar.commands.annotation.Optional; import co.aikar.commands.bukkit.contexts.OnlinePlayer; import dev.brighten.ac.Anticheat; import dev.brighten.ac.check.Check; import dev.brighten.ac.check.CheckData; import dev.brighten.ac.data.APlayer; -import dev.brighten.ac.gui.Logs; import dev.brighten.ac.handler.BBRevealHandler; import dev.brighten.ac.messages.Messages; import dev.brighten.ac.packet.handler.HandlerAbstract; -import dev.brighten.ac.utils.Color; -import dev.brighten.ac.utils.MiscUtils; -import dev.brighten.ac.utils.Pastebin; -import dev.brighten.ac.utils.Tuple; +import dev.brighten.ac.utils.*; import dev.brighten.ac.utils.annotation.Init; import dev.brighten.ac.utils.msg.ChatBuilder; import dev.brighten.ac.utils.reflections.Reflections; @@ -39,13 +34,13 @@ import org.bukkit.plugin.PluginDescriptionFile; import java.io.*; import java.nio.ByteBuffer; -import java.sql.Timestamp; -import java.time.format.DateTimeFormatter; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; import java.util.stream.Collectors; import java.util.zip.CRC32; -@Init +@Init(priority = Priority.LOW) @CommandAlias("kauri|anticheat|ac") @CommandPermission("anticheat.command") public class AnticheatCommand extends BaseCommand { @@ -216,78 +211,6 @@ public class AnticheatCommand extends BaseCommand { "You've been given a very special wand. Handle it responsibly.").color(ChatColor.GREEN).create()); } - @Subcommand("logs") - @Syntax("[player] [check]") - @CommandCompletion("@players @checkIds") - @CommandPermission("anticheat.command.logs") - @Description("Get player logs") - public void onLogs(CommandSender sender, @Single String playername, - @Single @Optional @Default("none") String check) { - UUID uuid = Bukkit.getOfflinePlayer(playername).getUniqueId(); - - sender.sendMessage(Color.Red + "Getting logs for " + playername + "..."); - - if(sender instanceof Player) { - if(check.equals("none")) { - Logs logs = new Logs(uuid); - - logs.showMenu((Player) sender); - } else { - Logs logs = new Logs(uuid, check); - - logs.showMenu((Player) sender); - } - } else { - List logs = new ArrayList<>(); - - if(check.equals("none")) { - Anticheat.INSTANCE.getLogManager().getLogs(uuid, logsList -> { - logsList.forEach(log -> { - logs.add("[" + new Timestamp(log.getTime()).toLocalDateTime() - .format(DateTimeFormatter.ISO_DATE_TIME) + "] funkemunky failed " - + Anticheat.INSTANCE.getCheckManager().getIdToName().get(log.getCheckId()) + "(VL: " - + log.getVl() + ") {" + log.getData() + "}"); - }); - if(logs.size() == 0) { - sender.sendMessage(Color.Gray + "There are no logs for player \"" + playername + "\""); - } else { - String url = null; - try { - url = Pastebin.makePaste(String.join("\n", logs), playername + "'s Logs", - Pastebin.Privacy.UNLISTED); - - sender.sendMessage(Color.Green + "Logs for " + playername + ": " + Color.White + url); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } - }); - } else { - Anticheat.INSTANCE.getLogManager().getLogs(uuid, check, logsList -> { - logsList.forEach(log -> { - logs.add("[" + new Timestamp(log.getTime()).toLocalDateTime() - .format(DateTimeFormatter.ISO_DATE_TIME) + "] funkemunky failed " - + Anticheat.INSTANCE.getCheckManager().getIdToName().get(log.getCheckId()) - + "(VL: " + log.getVl() + ") {" + log.getData() + "}"); - }); - if(logs.size() == 0) { - sender.sendMessage(Color.Gray + " does not have any violations for check \"" + check + "\""); - } else { - String url = null; - try { - url = Pastebin.makePaste(String.join("\n", logs), playername + "'s Logs", - Pastebin.Privacy.UNLISTED); - - sender.sendMessage(Color.Green + "Logs for " + playername + ": " + Color.White + url); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } - }); - } - } - } - @Subcommand("title") @Private public void onTitle(CommandSender sender, OnlinePlayer target, String title) { diff --git a/src/main/java/dev/brighten/ac/command/LogsCommand.java b/src/main/java/dev/brighten/ac/command/LogsCommand.java new file mode 100644 index 0000000..6663bd7 --- /dev/null +++ b/src/main/java/dev/brighten/ac/command/LogsCommand.java @@ -0,0 +1,240 @@ +package dev.brighten.ac.command; + +import co.aikar.commands.BaseCommand; +import co.aikar.commands.annotation.*; +import co.aikar.commands.annotation.Optional; +import dev.brighten.ac.Anticheat; +import dev.brighten.ac.check.CheckSettings; +import dev.brighten.ac.gui.Logs; +import dev.brighten.ac.logging.Log; +import dev.brighten.ac.utils.Color; +import dev.brighten.ac.utils.Pastebin; +import dev.brighten.ac.utils.Priority; +import dev.brighten.ac.utils.annotation.Init; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.io.*; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.sql.Timestamp; +import java.time.format.DateTimeFormatter; +import java.util.*; + +@Init(priority = Priority.LOW) +@CommandAlias("kauri|anticheat|ac") +@CommandPermission("anticheat.command") +public class LogsCommand extends BaseCommand { + + @Subcommand("logs") + @Syntax("[player] [check]") + @CommandCompletion("@players @checkIds") + @CommandPermission("anticheat.command.logs") + @Description("Get player logs") + public void onLogs(CommandSender sender, @Single String playername, + @Single @Optional @Default("none") String check) { + UUID uuid = Bukkit.getOfflinePlayer(playername).getUniqueId(); + + sender.sendMessage(Color.Red + "Getting logs for " + playername + "..."); + + if(sender instanceof Player) { + if(check.equals("none")) { + Logs logs = new Logs(uuid); + + logs.showMenu((Player) sender); + } else { + Logs logs = new Logs(uuid, check); + + logs.showMenu((Player) sender); + } + } else { + List logs = new ArrayList<>(); + + if(check.equals("none")) { + Anticheat.INSTANCE.getLogManager().getLogs(uuid, logsList -> { + logsList.forEach(log -> { + logs.add("[" + new Timestamp(log.getTime()).toLocalDateTime() + .format(DateTimeFormatter.ISO_DATE_TIME) + "] funkemunky failed " + + Anticheat.INSTANCE.getCheckManager().getIdToName().get(log.getCheckId()) + "(VL: " + + log.getVl() + ") {" + log.getData() + "}"); + }); + if(logs.size() == 0) { + sender.sendMessage(Color.Gray + "There are no logs for player \"" + playername + "\""); + } else { + String url = null; + try { + url = Pastebin.makePaste(String.join("\n", logs), playername + "'s Logs", + Pastebin.Privacy.UNLISTED); + + sender.sendMessage(Color.Green + "Logs for " + playername + ": " + Color.White + url); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + }); + } else { + Anticheat.INSTANCE.getLogManager().getLogs(uuid, check, logsList -> { + logsList.forEach(log -> { + logs.add("[" + new Timestamp(log.getTime()).toLocalDateTime() + .format(DateTimeFormatter.ISO_DATE_TIME) + "] funkemunky failed " + + Anticheat.INSTANCE.getCheckManager().getIdToName().get(log.getCheckId()) + + "(VL: " + log.getVl() + ") {" + log.getData() + "}"); + }); + if(logs.size() == 0) { + sender.sendMessage(Color.Gray + " does not have any violations for check \"" + check + "\""); + } else { + String url = null; + try { + url = Pastebin.makePaste(String.join("\n", logs), playername + "'s Logs", + Pastebin.Privacy.UNLISTED); + + sender.sendMessage(Color.Green + "Logs for " + playername + ": " + Color.White + url); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + }); + } + } + } + + @Subcommand("logs paste") + @CommandPermission("kauri.command.logs") + @Syntax("[player]") + @CommandCompletion("@players") + @Description("View logs via Pastebin") + public void onLogsPasteBin(CommandSender sender, String[] args) { + if(args.length == 0) { + sender.sendMessage(Color.Red + "Usage: /kauri logs web "); + return; + } + + String playername = args[0]; + + UUID uuid = Bukkit.getOfflinePlayer(playername).getUniqueId(); + + sender.sendMessage(Color.Red + "Getting logs for " + playername + "..."); + + if(sender instanceof Player) { + Logs logs = new Logs(uuid); + + logs.showMenu((Player) sender); + } else { + List logs = new ArrayList<>(); + + Anticheat.INSTANCE.getLogManager().getLogs(uuid, logsList -> { + logsList.forEach(log -> { + logs.add("[" + new Timestamp(log.getTime()).toLocalDateTime() + .format(DateTimeFormatter.ISO_DATE_TIME) + "] funkemunky failed " + + Anticheat.INSTANCE.getCheckManager().getIdToName().get(log.getCheckId()) + "(VL: " + + log.getVl() + ") {" + log.getData() + "}"); + }); + if(logs.size() == 0) { + sender.sendMessage(Color.Gray + "There are no logs for player \"" + playername + "\""); + } else { + String url = null; + try { + url = Pastebin.makePaste(String.join("\n", logs), playername + "'s Logs", + Pastebin.Privacy.UNLISTED); + + sender.sendMessage(Color.Green + "Logs for " + playername + ": " + Color.White + url); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + }); + } + } + + @Subcommand("logs web") + @CommandPermission("kauri.command.logs") + @Syntax("[player]") + @CommandCompletion("@players") + @Description("View the logs of a user") + public void onLogsWeb(CommandSender sender, String[] args) { + if(args.length == 0) { + if(sender instanceof Player) { + Player player = (Player) sender; + runWebLog(sender, player); + } else sender.sendMessage(Color.translate("You cannot view your own logs from console.")); + } else { + OfflinePlayer player = Bukkit.getOfflinePlayer(args[0]); + + if(player == null) { + sender.sendMessage(Color.translate("&cSomehow, out of hundreds of millions of" + + "Minecraft accounts, you found one that doesn't exist.")); + return; + } + + runWebLog(sender, player); + } + } + + private void runWebLog(CommandSender sender, OfflinePlayer target) { + //val logs = Kauri.INSTANCE.loggerManager.getLogs(target.getUniqueId()); + Anticheat.INSTANCE.getLogManager().getLogs(target.getUniqueId(), 100000, 0, logs -> { + Map violations = new HashMap<>(); + for (Log log : logs) { + violations.compute(log.getCheckId(), (name, count) -> { + if(count == null) { + return 1; + } + + return count + 1; + }); + } + + + StringBuilder url = new StringBuilder("https://funkemunky.cc/api/kauri?uuid=" + target.getUniqueId().toString().replaceAll("-", "") + (violations.keySet().size() > 0 ? "&violations=" : "")); + + if (violations.keySet().size() > 0) { + for (String key : violations.keySet()) { + if (Anticheat.INSTANCE.getCheckManager().isCheck(key)) { + CheckSettings checkData = Anticheat.INSTANCE.getCheckManager().getCheckSettings(Anticheat.INSTANCE.getCheckManager().getCheckClasses() + .get(Anticheat.INSTANCE.getCheckManager().getIdToName().get(key)).getCheckClass().getParent()); + int vl = violations.get(key), maxVL = checkData.getPunishVl(); + boolean developer = false; + + String toAppend = key + ":" + vl + ":" + maxVL + ":" + developer + ";"; + toAppend = toAppend.replaceAll(" ", "%20"); + + url.append(toAppend); + + } + } + + if (violations.keySet().size() > 0) { + url.deleteCharAt(url.length() - 1); + } + + String finalURL = "https://funkemunky.cc/api/kauri/cache/%id%"; + + try { + URL url2Run = new URL(url.toString()); + //%3F + BufferedReader reader = new BufferedReader(new InputStreamReader(url2Run + .openConnection().getInputStream(), StandardCharsets.UTF_8)); + + finalURL = finalURL.replace("%id%", readAll(reader)); + } catch (IOException e) { + e.printStackTrace(); + } + + sender.sendMessage(Color.translate("&aView the log here&7: &f" + finalURL)); + } else { + sender.sendMessage(Color.translate("&cPlayer has no logs.")); + } + }); + } + + private static String readAll(Reader rd) throws IOException { + StringBuilder sb = new StringBuilder(); + int cp; + while ((cp = rd.read()) != -1) { + sb.append((char) cp); + } + return sb.toString(); + } +} diff --git a/src/main/java/dev/brighten/ac/data/APlayer.java b/src/main/java/dev/brighten/ac/data/APlayer.java index 333ca42..4b752cc 100644 --- a/src/main/java/dev/brighten/ac/data/APlayer.java +++ b/src/main/java/dev/brighten/ac/data/APlayer.java @@ -13,12 +13,14 @@ import dev.brighten.ac.handler.MovementHandler; import dev.brighten.ac.handler.PotionHandler; import dev.brighten.ac.handler.VelocityHandler; import dev.brighten.ac.handler.block.BlockUpdateHandler; +import dev.brighten.ac.handler.entity.FakeMob; import dev.brighten.ac.handler.keepalive.KeepAlive; import dev.brighten.ac.handler.protocolsupport.ProtocolAPI; import dev.brighten.ac.messages.Messages; import dev.brighten.ac.packet.ProtocolVersion; import dev.brighten.ac.packet.handler.HandlerAbstract; import dev.brighten.ac.packet.wrapper.WPacket; +import dev.brighten.ac.packet.wrapper.objects.WrappedWatchableObject; import dev.brighten.ac.utils.KLocation; import dev.brighten.ac.utils.RunUtils; import dev.brighten.ac.utils.Tuple; @@ -26,10 +28,14 @@ import dev.brighten.ac.utils.objects.evicting.EvictingList; import dev.brighten.ac.utils.reflections.impl.MinecraftReflection; import dev.brighten.ac.utils.timer.Timer; import dev.brighten.ac.utils.timer.impl.MillisTimer; +import dev.brighten.ac.utils.world.types.RayCollision; import lombok.Getter; import lombok.Setter; import lombok.val; import net.minecraft.server.v1_8_R3.PacketPlayOutTransaction; +import org.bukkit.Achievement; +import org.bukkit.Location; +import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.util.Vector; @@ -89,6 +95,8 @@ public class APlayer { @Getter private final List> onVelocityTasks = new ArrayList<>(); public final EvictingList> pastLocations = new EvictingList<>(20); + @Getter + private FakeMob mob; @Setter @Getter @@ -124,18 +132,38 @@ public class APlayer { }); }); + // Removing inventory achievement + getBukkitPlayer().removeAchievement(Achievement.OPEN_INVENTORY); + // 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()); getBukkitPlayer().spigot().sendMessage(Messages.ALERTS_ON); } + + generateEntities(); + } + + private void generateEntities() { + mob = new FakeMob(EntityType.MAGMA_CUBE); + + KLocation origin = getMovement().getTo().getLoc().clone().add(0, 1.7, 0); + + RayCollision coll = new RayCollision(origin.toVector(), origin.getDirection().multiply(-1)); + + Location loc1 = coll.collisionPoint(2).toLocation(getBukkitPlayer().getWorld()); + + mob.spawn(true, loc1, + new ArrayList<>(Collections.singletonList( + new WrappedWatchableObject(0, 16, (byte) 1))), this); } protected void unload() { this.info = null; this.lagInfo = null; this.movement = null; + mob.despawn(); } diff --git a/src/main/java/dev/brighten/ac/data/PlayerRegistry.java b/src/main/java/dev/brighten/ac/data/PlayerRegistry.java index 8ebbd62..07f089b 100644 --- a/src/main/java/dev/brighten/ac/data/PlayerRegistry.java +++ b/src/main/java/dev/brighten/ac/data/PlayerRegistry.java @@ -10,7 +10,6 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.longs.LongArrayList; import it.unimi.dsi.fastutil.longs.LongList; import lombok.SneakyThrows; -import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.plugin.InvalidDescriptionException; import org.bukkit.plugin.Plugin; @@ -26,7 +25,6 @@ import java.util.zip.CRC32; public class PlayerRegistry { public PlayerRegistry() { - Bukkit.getOnlinePlayers().forEach(this::generate); checkIntegrity(); } public final Int2ObjectMap aplayerMap = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>()); diff --git a/src/main/java/dev/brighten/ac/data/info/GeneralInformation.java b/src/main/java/dev/brighten/ac/data/info/GeneralInformation.java index 218fcd9..8eac56b 100644 --- a/src/main/java/dev/brighten/ac/data/info/GeneralInformation.java +++ b/src/main/java/dev/brighten/ac/data/info/GeneralInformation.java @@ -31,11 +31,13 @@ public class GeneralInformation { lastRespawn = new TickTimer(), lastEntityCollision = new TickTimer(), lastWeb = new TickTimer(), lastLiquid = new TickTimer(), lastBlockDig = new TickTimer(), lastBlockPlace = new TickTimer(), lastBlockUpdate = new TickTimer(), lastMiscNear = new TickTimer(), lastHalfBlock = new TickTimer(), - lastFence = new TickTimer(), lastFakeBotHit = new TickTimer(); + lastFence = new TickTimer(), lastFakeBotHit = new TickTimer(), lastInventoryOpen = new TickTimer(), + botAttack = new TickTimer(); public LivingEntity target; public Optional groundJumpBoost; public boolean serverGround, lastServerGround, canFly, nearGround, worldLoaded, generalCancel, inVehicle, creative, - sneaking, lsneaking, sprinting, gliding, riptiding, wasOnSlime, onLadder, doingVelocity, breakingBlock; + sneaking, lsneaking, sprinting, gliding, riptiding, wasOnSlime, onLadder, doingVelocity, breakingBlock, + inventoryOpen; public List nearbyEntities = Collections.emptyList(); public PastLocation targetPastLocation = new PastLocation(); public KLocation lastKnownGoodPosition; diff --git a/src/main/java/dev/brighten/ac/handler/EntityLocationHandler.java b/src/main/java/dev/brighten/ac/handler/EntityLocationHandler.java index 5fe05e6..4751f2c 100644 --- a/src/main/java/dev/brighten/ac/handler/EntityLocationHandler.java +++ b/src/main/java/dev/brighten/ac/handler/EntityLocationHandler.java @@ -265,8 +265,10 @@ public class EntityLocationHandler { for (double offset : offsets) { FakeMob mob = new FakeMob(EntityType.MAGMA_CUBE); + // Setting Magma cube size to size 10 mob.spawn(true, location.clone().add(offset, offset, offset), - new ArrayList<>(Arrays.asList(new WrappedWatchableObject(0, 16, (byte)10))), data); + new ArrayList<>(Collections.singletonList( + new WrappedWatchableObject(0, 16, (byte) 10))), data); fakeMobToEntityId.put(mob.getEntityId(), entityId); diff --git a/src/main/java/dev/brighten/ac/handler/MovementHandler.java b/src/main/java/dev/brighten/ac/handler/MovementHandler.java index 02af16b..5a5532a 100644 --- a/src/main/java/dev/brighten/ac/handler/MovementHandler.java +++ b/src/main/java/dev/brighten/ac/handler/MovementHandler.java @@ -300,6 +300,8 @@ public class MovementHandler { lastFlying.reset(); + processBotMove(packet); + /* ata.playerInfo.generalCancel = data.getPlayer().getAllowFlight() || this.creativelastLastY @@ -342,6 +344,22 @@ it } } + private void processBotMove(WPacketPlayInFlying packet) { + if(packet.isMoved() || packet.isLooked()) { + KLocation origin = to.getLoc().clone().add(0, 1.7, 0); + + RayCollision coll = new RayCollision(origin.toVector(), origin.getDirection().multiply(-1)); + + Location loc1 = coll.collisionPoint(2.2).toLocation(player.getBukkitPlayer().getWorld()); + + if(player.getInfo().botAttack.isNotPassed(7)) { + loc1.setY(Math.max(origin.y + 1.2, loc1.getY())); + } else loc1.setY(Math.max(origin.y + 0.3, loc1.getY())); + + player.getMob().teleport(loc1.getX(), loc1.getY(), loc1.getZ(), loc1.getYaw(), loc1.getPitch()); + } + } + private static float getDeltaX(float yawDelta, float gcd) { return MathHelper.ceiling_float_int(yawDelta / gcd); } diff --git a/src/main/java/dev/brighten/ac/handler/PacketHandler.java b/src/main/java/dev/brighten/ac/handler/PacketHandler.java index 090d4a5..de714b5 100644 --- a/src/main/java/dev/brighten/ac/handler/PacketHandler.java +++ b/src/main/java/dev/brighten/ac/handler/PacketHandler.java @@ -294,6 +294,9 @@ public class PacketHandler { player.getEntityLocationHandler().removeFakeMob(targetId); player.getInfo().lastFakeBotHit.reset(); }); + if(player.getMob().getEntityId() == packet.getEntityId()) { + player.getInfo().botAttack.reset(); + } } else { Entity target = packet.getEntity(player.getBukkitPlayer().getWorld()); @@ -338,6 +341,32 @@ public class PacketHandler { player.getBlockUpdateHandler().onDig(packet); break; } + case CLIENT_COMMAND: { + WPacketPlayInClientCommand packet = (WPacketPlayInClientCommand) packetObject; + + if(packet.getCommand() == WPacketPlayInClientCommand.WrappedEnumClientCommand + .OPEN_INVENTORY_ACHIEVEMENT) { + player.getInfo().setInventoryOpen(true); + player.getInfo().lastInventoryOpen.reset(); + return true; + } + break; + } + case CLIENT_CLOSE_WINDOW: { + player.getInfo().setInventoryOpen(false); + break; + } + case SERVER_CLOSE_WINDOW: { + player.runKeepaliveAction(ka -> player.getInfo().setInventoryOpen(false)); + break; + } + case SERVER_OPEN_WINDOW: { + player.runKeepaliveAction(ka -> { + player.getInfo().setInventoryOpen(true); + player.getInfo().lastInventoryOpen.reset(); + }); + break; + } } if(player.sniffing) { diff --git a/src/main/java/dev/brighten/ac/listener/GeneralListener.java b/src/main/java/dev/brighten/ac/listener/GeneralListener.java index b0db79f..daccc1a 100644 --- a/src/main/java/dev/brighten/ac/listener/GeneralListener.java +++ b/src/main/java/dev/brighten/ac/listener/GeneralListener.java @@ -2,7 +2,11 @@ package dev.brighten.ac.listener; import dev.brighten.ac.Anticheat; import dev.brighten.ac.data.APlayer; +import dev.brighten.ac.packet.wrapper.objects.WrappedWatchableObject; +import dev.brighten.ac.utils.RunUtils; import dev.brighten.ac.utils.annotation.Init; +import dev.brighten.ac.utils.world.types.RayCollision; +import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -14,6 +18,9 @@ import org.bukkit.event.player.PlayerEditBookEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerTeleportEvent; +import java.util.ArrayList; +import java.util.Collections; + @Init public class GeneralListener implements Listener { @@ -50,7 +57,23 @@ public class GeneralListener implements Listener { if(event.getFrom().getWorld().equals(event.getTo().getWorld())) return; Anticheat.INSTANCE.getPlayerRegistry().getPlayer(event.getPlayer().getUniqueId()) - .ifPresent(player -> player.getBlockUpdateHandler().onWorldChange()); + .ifPresent(player -> { + player.getBlockUpdateHandler().onWorldChange(); + + // Updating bot loc when changing worlds + Location origin = event.getTo().clone().add(0, 1.7, 0); + + RayCollision coll = new RayCollision(origin.toVector(), origin.getDirection().multiply(-1)); + + Location loc1 = coll.collisionPoint(1.2).toLocation(event.getTo().getWorld()); + + RunUtils.taskLater(() -> { + player.getMob().despawn(); + player.getMob().spawn(true, loc1, + new ArrayList<>(Collections.singletonList( + new WrappedWatchableObject(0, 16, (byte) 1))), player); + }, 5); + }); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) diff --git a/src/main/java/dev/brighten/ac/packet/listener/PacketProcessor.java b/src/main/java/dev/brighten/ac/packet/listener/PacketProcessor.java index 02b4abe..887d390 100644 --- a/src/main/java/dev/brighten/ac/packet/listener/PacketProcessor.java +++ b/src/main/java/dev/brighten/ac/packet/listener/PacketProcessor.java @@ -133,6 +133,7 @@ public class PacketProcessor { public Object call(Player player, Object packet, PacketType type) { if(packet == null) return false; + PacketInfo info = new PacketInfo(player, packet, type, System.currentTimeMillis()), asyncInfo; boolean cancelled = false; diff --git a/src/main/java/dev/brighten/ac/packet/wrapper/PacketConverter.java b/src/main/java/dev/brighten/ac/packet/wrapper/PacketConverter.java index 9e7c033..04bc8fc 100644 --- a/src/main/java/dev/brighten/ac/packet/wrapper/PacketConverter.java +++ b/src/main/java/dev/brighten/ac/packet/wrapper/PacketConverter.java @@ -90,4 +90,8 @@ public interface PacketConverter { WPacketPlayOutMapChunk processMapChunk(Object object); WPacketPlayOutMapChunkBulk processMapChunkBulk(Object packet); + + WPacketPlayInClientCommand processInClientCommand(Object packet); + + WPacketPlayInWindowClick processInWindowClick(Object packet); } diff --git a/src/main/java/dev/brighten/ac/packet/wrapper/PacketType.java b/src/main/java/dev/brighten/ac/packet/wrapper/PacketType.java index 88769a9..62384f0 100644 --- a/src/main/java/dev/brighten/ac/packet/wrapper/PacketType.java +++ b/src/main/java/dev/brighten/ac/packet/wrapper/PacketType.java @@ -25,7 +25,7 @@ public enum PacketType { BLOCK_DIG("PacketPlayInBlockDig"), BLOCK_PLACE("PacketPlayInBlockPlace"), CHAT("PacketPlayInChat"), - CLIENT_COMMAND("PacketPlayInCommand"), + CLIENT_COMMAND("PacketPlayInClientCommand"), CLIENT_CLOSE_WINDOW("PacketPlayInCloseWindow"), ENTITY_ACTION("PacketPlayInEntityAction"), ENTITY_EFFECT("PacketPlayOutEntityEffect"), @@ -153,6 +153,10 @@ public enum PacketType { return convert.processMapChunk(object); case MAP_CHUNK_BULK: return convert.processMapChunkBulk(object); + case CLIENT_COMMAND: + return convert.processInClientCommand(object); + case WINDOW_CLICK: + return convert.processInWindowClick(object); default: return object; } diff --git a/src/main/java/dev/brighten/ac/packet/wrapper/impl/Processor_18.java b/src/main/java/dev/brighten/ac/packet/wrapper/impl/Processor_18.java index c08cfb1..bfb22e0 100644 --- a/src/main/java/dev/brighten/ac/packet/wrapper/impl/Processor_18.java +++ b/src/main/java/dev/brighten/ac/packet/wrapper/impl/Processor_18.java @@ -793,6 +793,26 @@ public class Processor_18 implements PacketConverter { return new WPacketPlayOutMapChunkBulk(chunks); } + @Override + public WPacketPlayInClientCommand processInClientCommand(Object packet) { + PacketPlayInClientCommand clientCommand = (PacketPlayInClientCommand) packet; + + return new WPacketPlayInClientCommand(WPacketPlayInClientCommand + .WrappedEnumClientCommand.valueOf(clientCommand.a().name())); + } + + @Override + public WPacketPlayInWindowClick processInWindowClick(Object packet) { + PacketPlayInWindowClick windowClick = (PacketPlayInWindowClick) packet; + + + return WPacketPlayInWindowClick.builder().windowId(windowClick.a()) + .slot(windowClick.b()).button(windowClick.c()) + .action(windowClick.d()).mode(windowClick.f()) + .clickedItem(windowClick.e() == null ? null : CraftItemStack.asBukkitCopy(windowClick.e())) + .build(); + } + private static void processChunk(byte[] locs, int size, int chunkX, int chunkZ, boolean groundUp, Map blocks) { ChunkSection[] sections = new ChunkSection[16]; diff --git a/src/main/java/dev/brighten/ac/packet/wrapper/in/WPacketPlayInWindowClick.java b/src/main/java/dev/brighten/ac/packet/wrapper/in/WPacketPlayInWindowClick.java new file mode 100644 index 0000000..78173bd --- /dev/null +++ b/src/main/java/dev/brighten/ac/packet/wrapper/in/WPacketPlayInWindowClick.java @@ -0,0 +1,26 @@ +package dev.brighten.ac.packet.wrapper.in; + +import dev.brighten.ac.packet.wrapper.PacketType; +import dev.brighten.ac.packet.wrapper.WPacket; +import lombok.Builder; +import lombok.Getter; +import org.bukkit.inventory.ItemStack; + +@Getter +@Builder +public class WPacketPlayInWindowClick extends WPacket { + + private int windowId, slot, button, mode; + private short action; + private ItemStack clickedItem; + + @Override + public PacketType getPacketType() { + return PacketType.WINDOW_CLICK; + } + + @Override + public Object getPacket() { + return null; + } +} diff --git a/src/main/java/dev/brighten/ac/packet/wrapper/out/WPacketPlayInClientCommand.java b/src/main/java/dev/brighten/ac/packet/wrapper/out/WPacketPlayInClientCommand.java new file mode 100644 index 0000000..d638792 --- /dev/null +++ b/src/main/java/dev/brighten/ac/packet/wrapper/out/WPacketPlayInClientCommand.java @@ -0,0 +1,29 @@ +package dev.brighten.ac.packet.wrapper.out; + +import dev.brighten.ac.packet.wrapper.PacketType; +import dev.brighten.ac.packet.wrapper.WPacket; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class WPacketPlayInClientCommand extends WPacket { + + private WrappedEnumClientCommand command; + + @Override + public PacketType getPacketType() { + return PacketType.CLIENT_COMMAND; + } + + @Override + public Object getPacket() { + return null; + } + + public enum WrappedEnumClientCommand { + PERFORM_RESPAWN, + REQUEST_STATS, + OPEN_INVENTORY_ACHIEVEMENT; + } +} diff --git a/src/main/java/dev/brighten/ac/utils/Helper.java b/src/main/java/dev/brighten/ac/utils/Helper.java index 69b9607..2dfbfbe 100644 --- a/src/main/java/dev/brighten/ac/utils/Helper.java +++ b/src/main/java/dev/brighten/ac/utils/Helper.java @@ -22,347 +22,379 @@ import java.util.*; import java.util.stream.Collectors; import java.util.stream.IntStream; +/** + * @author DeprecatedLuke + * Taken from https://github.com/DeprecatedLuke/fireflyx/blob/master/src/main/java/com/ngxdev/anticheat/utils/Helper.java + */ public class Helper { - public static int angularDistance(double alpha, double beta) { - while (alpha < 0) alpha += 360; - while (beta < 0) beta += 360; - double phi = Math.abs(beta - alpha) % 360; - return (int) (phi > 180 ? 360 - phi : phi); - } + public static Vector vector(double yaw, double pitch) { + Vector vector = new Vector(); + vector.setY(-Math.sin(Math.toRadians(pitch))); + double xz = Math.cos(Math.toRadians(pitch)); + vector.setX(-xz * Math.sin(Math.toRadians(yaw))); + vector.setZ(xz * Math.cos(Math.toRadians(yaw))); + return vector; + } - public static Vector vector(double yaw, double pitch) { - Vector vector = new Vector(); - vector.setY(-Math.sin(Math.toRadians(pitch))); - double xz = Math.cos(Math.toRadians(pitch)); - vector.setX(-xz * Math.sin(Math.toRadians(yaw))); - vector.setZ(xz * Math.cos(Math.toRadians(yaw))); - return vector; - } + public static void drawRay(RayCollision collision, double distance, EnumParticle particle, Collection players) { + for (double i = 0; i < distance; i += 0.2) { + float fx = (float) (collision.originX + (collision.directionX * i)); + float fy = (float) (collision.originY + (collision.directionY * i)); + float fz = (float) (collision.originZ + (collision.directionZ * i)); - public static void drawRay(RayCollision collision, double distance, EnumParticle particle, Collection players) { - for (double i = 0; i < 3; i += 0.2) { - float fx = (float) (collision.originX + (collision.directionX * i)); - float fy = (float) (collision.originY + (collision.directionY * i)); - float fz = (float) (collision.originZ + (collision.directionZ * i)); - - WPacketPlayOutWorldParticles packet = WPacketPlayOutWorldParticles.builder() - .particle(particle) - .x(fx) - .y(fy) - .z(fz) - .offsetX(0) - .offsetY(0) - .offsetZ(0) - .speed(0) - .amount(1) - .longD(true) - .data(new int[0]) - .build(); - players.forEach(p -> HandlerAbstract.getHandler().sendPacketSilently(p, packet)); - } - } + WPacketPlayOutWorldParticles packet = WPacketPlayOutWorldParticles.builder() + .particle(particle) + .x(fx) + .y(fy) + .z(fz) + .offsetX(0) + .offsetY(0) + .offsetZ(0) + .speed(0) + .amount(1) + .longD(true) + .data(new int[0]) + .build(); + players.forEach(p -> HandlerAbstract.getHandler().sendPacketSilently(p, packet)); + } + } - public static void drawCuboid(SimpleCollisionBox box, EnumParticle particle, Collection players) { - Step.GenericStepper x = Step.step((float)box.minX, 0.241F, (float)box.maxX); - Step.GenericStepper y = Step.step((float)box.minY, 0.241F, (float)box.maxY); - Step.GenericStepper z = Step.step((float)box.minZ, 0.241F, (float)box.maxZ); - Iterator var6 = x.iterator(); + public static void drawCuboid(SimpleCollisionBox box, EnumParticle particle, Collection players) { + Step.GenericStepper x = Step.step((float) box.minX, 0.241F, (float) box.maxX); + Step.GenericStepper y = Step.step((float) box.minY, 0.241F, (float) box.maxY); + Step.GenericStepper z = Step.step((float) box.minZ, 0.241F, (float) box.maxZ); + Iterator var6 = x.iterator(); - while(var6.hasNext()) { - float fx = (Float)var6.next(); - Iterator var8 = y.iterator(); + while (var6.hasNext()) { + float fx = (Float) var6.next(); + Iterator var8 = y.iterator(); - label61: - while(var8.hasNext()) { - float fy = (Float)var8.next(); - Iterator var10 = z.iterator(); + label61: + while (var8.hasNext()) { + float fy = (Float) var8.next(); + Iterator var10 = z.iterator(); - while(true) { - float fz; - int check; - do { - if (!var10.hasNext()) { - continue label61; - } + while (true) { + float fz; + int check; + do { + if (!var10.hasNext()) { + continue label61; + } - fz = (Float)var10.next(); - check = 0; - if (x.first() || x.last()) { - ++check; - } + fz = (Float) var10.next(); + check = 0; + if (x.first() || x.last()) { + ++check; + } - if (y.first() || y.last()) { - ++check; - } + if (y.first() || y.last()) { + ++check; + } - if (z.first() || z.last()) { - ++check; - } - } while(check < 2); + if (z.first() || z.last()) { + ++check; + } + } while (check < 2); - WPacketPlayOutWorldParticles packet = WPacketPlayOutWorldParticles.builder() - .particle(particle) - .x(fx) - .y(fy) - .z(fz) - .offsetX(0) - .offsetY(0) - .offsetZ(0) - .speed(0) - .amount(1) - .data(new int[0]) - .build(); + WPacketPlayOutWorldParticles packet = WPacketPlayOutWorldParticles.builder() + .particle(particle) + .x(fx) + .y(fy) + .z(fz) + .offsetX(0) + .offsetY(0) + .offsetZ(0) + .speed(0) + .amount(1) + .data(new int[0]) + .build(); - Iterator var14 = players.iterator(); + Iterator var14 = players.iterator(); - while(var14.hasNext()) { - Player p = var14.next(); - HandlerAbstract.getHandler().sendPacketSilently(p, packet); - } - } - } - } + while (var14.hasNext()) { + Player p = var14.next(); + HandlerAbstract.getHandler().sendPacketSilently(p, packet); + } + } + } + } - } + } - public static void drawPoint(Vector point, EnumParticle particle, Collection players) { - WPacketPlayOutWorldParticles packet = WPacketPlayOutWorldParticles.builder() - .particle(particle) - .x((float)point.getX()) - .y((float)point.getY()) - .z((float)point.getZ()) - .offsetX(0) - .offsetY(0) - .offsetZ(0) - .speed(0) - .amount(1) - .data(new int[0]) - .build(); - Iterator var4 = players.iterator(); + public static void drawPoint(Vector point, EnumParticle particle, Collection players) { + WPacketPlayOutWorldParticles packet = WPacketPlayOutWorldParticles.builder() + .particle(particle) + .x((float) point.getX()) + .y((float) point.getY()) + .z((float) point.getZ()) + .offsetX(0) + .offsetY(0) + .offsetZ(0) + .speed(0) + .amount(1) + .data(new int[0]) + .build(); + Iterator var4 = players.iterator(); - while(var4.hasNext()) { - Player p = var4.next(); - HandlerAbstract.getHandler().sendPacketSilently(p, packet); - } + while (var4.hasNext()) { + Player p = var4.next(); + HandlerAbstract.getHandler().sendPacketSilently(p, packet); + } - } + } - public static Block getBlockAt(World world, int x, int y, int z) { - return world.isChunkLoaded(x >> 4, z >> 4) - ? world.getChunkAt(x >> 4, z >> 4).getBlock(x & 15, y, z & 15) - : null; - } + public static Block getBlockAt(World world, int x, int y, int z) { + return world.isChunkLoaded(x >> 4, z >> 4) + ? world.getChunkAt(x >> 4, z >> 4).getBlock(x & 15, y, z & 15) + : null; + } - public static SimpleCollisionBox wrap(SimpleCollisionBox a, SimpleCollisionBox b) { - double minX = Math.min(a.minX, b.minX); - double minY = Math.min(a.minY, b.minY); - double minZ = Math.min(a.minZ, b.minZ); - double maxX = Math.max(a.maxX, b.maxX); - double maxY = Math.max(a.maxY, b.maxY); - double maxZ = Math.max(a.maxZ, b.maxZ); - return new SimpleCollisionBox(minX, minY, minZ, maxX, maxY, maxZ); - } + public static SimpleCollisionBox wrap(SimpleCollisionBox a, SimpleCollisionBox b) { + double minX = Math.min(a.minX, b.minX); + double minY = Math.min(a.minY, b.minY); + double minZ = Math.min(a.minZ, b.minZ); + double maxX = Math.max(a.maxX, b.maxX); + double maxY = Math.max(a.maxY, b.maxY); + double maxZ = Math.max(a.maxZ, b.maxZ); + return new SimpleCollisionBox(minX, minY, minZ, maxX, maxY, maxZ); + } - public static SimpleCollisionBox wrap(List box) { - if (!box.isEmpty()) { - SimpleCollisionBox wrap = box.get(0).copy(); - for (int i = 1; i < box.size(); i++) { - SimpleCollisionBox a = box.get(i); - if (wrap.minX > a.minX) wrap.minX = a.minX; - if (wrap.minY > a.minY) wrap.minY = a.minY; - if (wrap.minZ > a.minZ) wrap.minZ = a.minZ; - if (wrap.maxX < a.maxX) wrap.maxX = a.maxX; - if (wrap.maxY < a.maxY) wrap.maxY = a.maxY; - if (wrap.maxZ < a.maxZ) wrap.maxZ = a.maxZ; - } - return wrap; - } - return null; - } + public static SimpleCollisionBox wrap(List box) { + if (!box.isEmpty()) { + SimpleCollisionBox wrap = box.get(0).copy(); + for (int i = 1; i < box.size(); i++) { + SimpleCollisionBox a = box.get(i); + if (wrap.minX > a.minX) wrap.minX = a.minX; + if (wrap.minY > a.minY) wrap.minY = a.minY; + if (wrap.minZ > a.minZ) wrap.minZ = a.minZ; + if (wrap.maxX < a.maxX) wrap.maxX = a.maxX; + if (wrap.maxY < a.maxY) wrap.maxY = a.maxY; + if (wrap.maxZ < a.maxZ) wrap.maxZ = a.maxZ; + } + return wrap; + } + return null; + } - public static List blockCollisions(List blocks, CollisionBox box) { - return blocks.stream() - .filter(b -> BlockData.getData(b.getType()).getBox(b, ProtocolVersion.getGameVersion()).isCollided(box)) - .collect(Collectors.toCollection(LinkedList::new)); - } + public static List blockCollisions(List blocks, CollisionBox box) { + return blocks.stream() + .filter(b -> BlockData.getData(b.getType()).getBox(b, ProtocolVersion.getGameVersion()).isCollided(box)) + .collect(Collectors.toCollection(LinkedList::new)); + } - public static boolean isCollided(SimpleCollisionBox toCheck, CollisionBox other) { - List downcasted = new ArrayList<>(); + public static boolean isCollided(SimpleCollisionBox toCheck, CollisionBox other) { + List downcasted = new ArrayList<>(); - other.downCast(downcasted); + other.downCast(downcasted); - return downcasted.stream().anyMatch(box -> box.maxX >= toCheck.minX && box.minX <= toCheck.maxX - && box.maxY >= toCheck.minY && box.minY <= toCheck.maxY && box.maxZ >= toCheck.minZ - && box.minZ <= toCheck.maxZ); - } + return downcasted.stream().anyMatch(box -> box.maxX >= toCheck.minX && box.minX <= toCheck.maxX + && box.maxY >= toCheck.minY && box.minY <= toCheck.maxY && box.maxZ >= toCheck.minZ + && box.minZ <= toCheck.maxZ); + } - public static List blockCollisions(List blocks, CollisionBox box, int material) { - return blocks.stream().filter(b -> Materials.checkFlag(b.getType(), material)) - .filter(b -> BlockData.getData(b.getType()).getBox(b, ProtocolVersion.getGameVersion()).isCollided(box)) - .collect(Collectors.toCollection(LinkedList::new)); - } + public static List blockCollisions(List blocks, CollisionBox box, int material) { + return blocks.stream().filter(b -> Materials.checkFlag(b.getType(), material)) + .filter(b -> BlockData.getData(b.getType()).getBox(b, ProtocolVersion.getGameVersion()).isCollided(box)) + .collect(Collectors.toCollection(LinkedList::new)); + } - public static List collisions(List boxes, CollisionBox box) { - return boxes.stream().filter(b -> b.isCollided(box)) - .collect(Collectors.toCollection(LinkedList::new)); - } + public static List collisions(List boxes, CollisionBox box) { + return boxes.stream().filter(b -> b.isCollided(box)) + .collect(Collectors.toCollection(LinkedList::new)); + } - public static List getCollisions(World world, SimpleCollisionBox collisionBox, int mask) { - int x1 = (int) Math.floor(collisionBox.minX); - int y1 = (int) Math.floor(collisionBox.minY); - int z1 = (int) Math.floor(collisionBox.minZ); - int x2 = (int) Math.floor(collisionBox.maxX + 1); - int y2 = (int) Math.floor(collisionBox.maxY + 1); - int z2 = (int) Math.floor(collisionBox.maxZ + 1); - List collisionBoxes = new ArrayList<>(); - Block block; - for (int x = x1; x < x2; ++x) - for (int y = y1 - 1; y < y2; ++y) - for (int z = z1; z < z2; ++z) - if ((block = getBlockAt(world, x, y, z)) != null - && BlockUtils.getXMaterial(block.getType()) != XMaterial.AIR) - if (Materials.checkFlag(block.getType(),mask)) { - CollisionBox box = BlockData.getData(block.getType()) - .getBox(block, ProtocolVersion.getGameVersion()); + public static List getCollisions(World world, SimpleCollisionBox collisionBox, int mask) { + int x1 = (int) Math.floor(collisionBox.minX); + int y1 = (int) Math.floor(collisionBox.minY); + int z1 = (int) Math.floor(collisionBox.minZ); + int x2 = (int) Math.floor(collisionBox.maxX + 1); + int y2 = (int) Math.floor(collisionBox.maxY + 1); + int z2 = (int) Math.floor(collisionBox.maxZ + 1); + List collisionBoxes = new ArrayList<>(); + Block block; + for (int x = x1; x < x2; ++x) + for (int y = y1 - 1; y < y2; ++y) + for (int z = z1; z < z2; ++z) + if ((block = getBlockAt(world, x, y, z)) != null + && BlockUtils.getXMaterial(block.getType()) != XMaterial.AIR) + if (Materials.checkFlag(block.getType(), mask)) { + CollisionBox box = BlockData.getData(block.getType()) + .getBox(block, ProtocolVersion.getGameVersion()); - if(box.isIntersected(collisionBox)) { - box.downCast(collisionBoxes); - } - } - return collisionBoxes; - } + if (box.isIntersected(collisionBox)) { + box.downCast(collisionBoxes); + } + } + return collisionBoxes; + } - public static List getCollisions(APlayer player, SimpleCollisionBox collisionBox) { - return getCollisions(player, collisionBox, Materials.COLLIDABLE); - } + public static List getCollisions(APlayer player, SimpleCollisionBox collisionBox) { + return getCollisions(player, collisionBox, Materials.COLLIDABLE); + } - public static SimpleCollisionBox getEntityCollision(Entity entity) { - return new SimpleCollisionBox((Object)MinecraftReflection.getEntityBoundingBox(entity)); - } + public static SimpleCollisionBox getEntityCollision(Entity entity) { + return new SimpleCollisionBox((Object) MinecraftReflection.getEntityBoundingBox(entity)); + } - public static List getCollisions(APlayer player, SimpleCollisionBox collisionBox, int mask) { - int x1 = (int) Math.floor(collisionBox.minX); - int y1 = (int) Math.floor(collisionBox.minY); - int z1 = (int) Math.floor(collisionBox.minZ); - int x2 = (int) Math.floor(collisionBox.maxX + 1); - int y2 = (int) Math.floor(collisionBox.maxY + 1); - int z2 = (int) Math.floor(collisionBox.maxZ + 1); - List collisionBoxes = new ArrayList<>(); - for (int x = x1; x < x2; ++x) - for (int y = y1 - 1; y < y2; ++y) - for (int z = z1; z < z2; ++z) { - IntVector vec = new IntVector(x, y, z); - Material type = player.getBlockUpdateHandler().getBlock(vec).getType(); + public static List getCollisions(APlayer player, SimpleCollisionBox collisionBox, int mask) { + int x1 = (int) Math.floor(collisionBox.minX); + int y1 = (int) Math.floor(collisionBox.minY); + int z1 = (int) Math.floor(collisionBox.minZ); + int x2 = (int) Math.floor(collisionBox.maxX + 1); + int y2 = (int) Math.floor(collisionBox.maxY + 1); + int z2 = (int) Math.floor(collisionBox.maxZ + 1); + List collisionBoxes = new ArrayList<>(); + for (int x = x1; x < x2; ++x) + for (int y = y1 - 1; y < y2; ++y) + for (int z = z1; z < z2; ++z) { + IntVector vec = new IntVector(x, y, z); + Material type = player.getBlockUpdateHandler().getBlock(vec).getType(); - if(type != Material.AIR && Materials.checkFlag(type, mask)) { - CollisionBox box = BlockData.getData(type) - .getBox(player, vec, ProtocolVersion.getGameVersion()); + if (type != Material.AIR && Materials.checkFlag(type, mask)) { + CollisionBox box = BlockData.getData(type) + .getBox(player, vec, ProtocolVersion.getGameVersion()); - if(box.isIntersected(collisionBox)) { - box.downCast(collisionBoxes); - } - } - } + if (box.isIntersected(collisionBox)) { + box.downCast(collisionBoxes); + } + } + } - for (Entity entity : player.getInfo().getNearbyEntities()) { - if(!BlockUtils.isEntityCollidable(entity)) continue; + for (Entity entity : player.getInfo().getNearbyEntities()) { + if (!BlockUtils.isEntityCollidable(entity)) continue; - SimpleCollisionBox entityCollisionBox = new SimpleCollisionBox(ReflectionsUtil.getBoundingBox(entity)); + SimpleCollisionBox entityCollisionBox = new SimpleCollisionBox(ReflectionsUtil.getBoundingBox(entity)); - if(entityCollisionBox.isIntersected(collisionBox)) - entityCollisionBox.downCast(collisionBoxes); - } + if (entityCollisionBox.isIntersected(collisionBox)) + entityCollisionBox.downCast(collisionBoxes); + } - return collisionBoxes; - } + return collisionBoxes; + } - public static List getCollisionsNoEntities(APlayer player, - SimpleCollisionBox collisionBox, int mask) { - int x1 = (int) Math.floor(collisionBox.minX); - int y1 = (int) Math.floor(collisionBox.minY); - int z1 = (int) Math.floor(collisionBox.minZ); - int x2 = (int) Math.floor(collisionBox.maxX + 1); - int y2 = (int) Math.floor(collisionBox.maxY + 1); - int z2 = (int) Math.floor(collisionBox.maxZ + 1); - List collisionBoxes = new ArrayList<>(); - for (int x = x1; x < x2; ++x) - for (int y = y1 - 1; y < y2; ++y) - for (int z = z1; z < z2; ++z) { - IntVector vec = new IntVector(x, y, z); - Material type = player.getBlockUpdateHandler().getBlock(vec).getType(); + public static List> + getCollisionsWithTypeNoEntities(APlayer player, SimpleCollisionBox collisionBox) { + return getCollisionsWithTypeNoEntities(player, collisionBox, Materials.COLLIDABLE); + } - if(type != Material.AIR && Materials.checkFlag(type, mask)) { - CollisionBox box = BlockData.getData(type) - .getBox(player, vec, ProtocolVersion.getGameVersion()); + public static List> + getCollisionsWithTypeNoEntities(APlayer player, SimpleCollisionBox collisionBox, int mask) { + int x1 = (int) Math.floor(collisionBox.minX); + int y1 = (int) Math.floor(collisionBox.minY); + int z1 = (int) Math.floor(collisionBox.minZ); + int x2 = (int) Math.floor(collisionBox.maxX + 1); + int y2 = (int) Math.floor(collisionBox.maxY + 1); + int z2 = (int) Math.floor(collisionBox.maxZ + 1); + List> collisionBoxes = new ArrayList<>(); + for (int x = x1; x < x2; ++x) + for (int y = y1 - 1; y < y2; ++y) + for (int z = z1; z < z2; ++z) { + IntVector vec = new IntVector(x, y, z); + Material type = player.getBlockUpdateHandler().getBlock(vec).getType(); - if(box.isIntersected(collisionBox)) { - box.downCast(collisionBoxes); - } - } - } + if (type != Material.AIR && Materials.checkFlag(type, mask)) { + CollisionBox box = BlockData.getData(type) + .getBox(player, vec, ProtocolVersion.getGameVersion()); - return collisionBoxes; - } + if (box.isIntersected(collisionBox)) { + for (SimpleCollisionBox simpleCollisionBox : box.downCast()) { + collisionBoxes.add(new Tuple<>(simpleCollisionBox, type)); + } + } + } + } - public static List getBlocksNearby2(World world, SimpleCollisionBox collisionBox, int mask) { - int x1 = (int) Math.floor(collisionBox.minX); - int y1 = (int) Math.floor(collisionBox.minY); - int z1 = (int) Math.floor(collisionBox.minZ); - int x2 = (int) Math.ceil(collisionBox.maxX); - int y2 = (int) Math.ceil(collisionBox.maxY); - int z2 = (int) Math.ceil(collisionBox.maxZ); - List blocks = new LinkedList<>(); - Block block; - for (int x = x1; x <= x2; x++) - for (int y = y1; y <= y2; y++) - for (int z = z1; z <= z2; z++) - if ((block = getBlockAt(world, x, y, z)) != null - && BlockUtils.getXMaterial(block.getType()) != XMaterial.AIR) - if (Materials.checkFlag(block.getType(),mask)) - blocks.add(block); - return blocks; - } + return collisionBoxes; + } - private static final int[] decimalPlaces = {0, 10, 100, 1000, 10000, 100000, 1000000, - 10000000, 100000000, 1000000000}; + public static List getCollisionsNoEntities(APlayer player, + SimpleCollisionBox collisionBox, int mask) { + int x1 = (int) Math.floor(collisionBox.minX); + int y1 = (int) Math.floor(collisionBox.minY); + int z1 = (int) Math.floor(collisionBox.minZ); + int x2 = (int) Math.floor(collisionBox.maxX + 1); + int y2 = (int) Math.floor(collisionBox.maxY + 1); + int z2 = (int) Math.floor(collisionBox.maxZ + 1); + List collisionBoxes = new ArrayList<>(); + for (int x = x1; x < x2; ++x) + for (int y = y1 - 1; y < y2; ++y) + for (int z = z1; z < z2; ++z) { + IntVector vec = new IntVector(x, y, z); + Material type = player.getBlockUpdateHandler().getBlock(vec).getType(); - public static double format(double d, int dec) { - return (long) (d * decimalPlaces[dec] + 0.5) / (double) decimalPlaces[dec]; - } + if (type != Material.AIR && Materials.checkFlag(type, mask)) { + CollisionBox box = BlockData.getData(type) + .getBox(player, vec, ProtocolVersion.getGameVersion()); - public static String drawUsage(long max, long time) { - double chunk = max / 50.; - String line = IntStream.range(0, 50).mapToObj(i -> (chunk * i < time ? "§c" : "§7") + "❘") - .collect(Collectors.joining("", "[", "")); - String zeros = "00"; - String nums = Integer.toString((int) ((time / (double) max) * 100)); - return line + "§f] §c" + zeros.substring(0, 3 - nums.length()) + nums + "% §f❘"; - } + if (box.isIntersected(collisionBox)) { + box.downCast(collisionBoxes); + } + } + } - public static String drawUsage(long max, double time) { - double chunk = max / 50.; - String line = IntStream.range(0, 50).mapToObj(i -> (chunk * i < time ? "§c" : "§7") + "❘") - .collect(Collectors.joining("", "[", "")); - String nums = String.valueOf(format((time / (double) max) * 100, 3)); - return line + "§f] §c" + nums + "%"; - } + return collisionBoxes; + } - public static List toCollisions(List blocks) { - return blocks.stream().map(b -> BlockData.getData(b.getType()).getBox(b, ProtocolVersion.getGameVersion())) - .collect(Collectors.toCollection(LinkedList::new)); - } + public static List getBlocksNearby2(World world, SimpleCollisionBox collisionBox, int mask) { + int x1 = (int) Math.floor(collisionBox.minX); + int y1 = (int) Math.floor(collisionBox.minY); + int z1 = (int) Math.floor(collisionBox.minZ); + int x2 = (int) Math.ceil(collisionBox.maxX); + int y2 = (int) Math.ceil(collisionBox.maxY); + int z2 = (int) Math.ceil(collisionBox.maxZ); + List blocks = new LinkedList<>(); + Block block; + for (int x = x1; x <= x2; x++) + for (int y = y1; y <= y2; y++) + for (int z = z1; z <= z2; z++) + if ((block = getBlockAt(world, x, y, z)) != null + && BlockUtils.getXMaterial(block.getType()) != XMaterial.AIR) + if (Materials.checkFlag(block.getType(), mask)) + blocks.add(block); + return blocks; + } - public static List toCollisionsDowncasted(List blocks) { - List collisions = new LinkedList<>(); - blocks.forEach(b -> BlockData.getData(b.getType()) - .getBox(b, ProtocolVersion.getGameVersion()).downCast(collisions)); - return collisions; - } + private static final int[] decimalPlaces = {0, 10, 100, 1000, 10000, 100000, 1000000, + 10000000, 100000000, 1000000000}; - public static CollisionBox toCollisions(Block b) { - return BlockData.getData(b.getType()).getBox(b, ProtocolVersion.getGameVersion()); - } + public static double format(double d, int dec) { + return (long) (d * decimalPlaces[dec] + 0.5) / (double) decimalPlaces[dec]; + } + + public static String drawUsage(long max, long time) { + double chunk = max / 50.; + String line = IntStream.range(0, 50).mapToObj(i -> (chunk * i < time ? "§c" : "§7") + "❘") + .collect(Collectors.joining("", "[", "")); + String zeros = "00"; + String nums = Integer.toString((int) ((time / (double) max) * 100)); + return line + "§f] §c" + zeros.substring(0, 3 - nums.length()) + nums + "% §f❘"; + } + + public static String drawUsage(long max, double time) { + double chunk = max / 50.; + String line = IntStream.range(0, 50).mapToObj(i -> (chunk * i < time ? "§c" : "§7") + "❘") + .collect(Collectors.joining("", "[", "")); + String nums = String.valueOf(format((time / (double) max) * 100, 3)); + return line + "§f] §c" + nums + "%"; + } + + public static List toCollisions(List blocks) { + return blocks.stream().map(b -> BlockData.getData(b.getType()).getBox(b, ProtocolVersion.getGameVersion())) + .collect(Collectors.toCollection(LinkedList::new)); + } + + public static List toCollisionsDowncasted(List blocks) { + List collisions = new LinkedList<>(); + blocks.forEach(b -> BlockData.getData(b.getType()) + .getBox(b, ProtocolVersion.getGameVersion()).downCast(collisions)); + return collisions; + } + + public static CollisionBox toCollisions(Block b) { + return BlockData.getData(b.getType()).getBox(b, ProtocolVersion.getGameVersion()); + } } diff --git a/src/main/java/dev/brighten/ac/utils/KLocation.java b/src/main/java/dev/brighten/ac/utils/KLocation.java index f372efe..8437a17 100644 --- a/src/main/java/dev/brighten/ac/utils/KLocation.java +++ b/src/main/java/dev/brighten/ac/utils/KLocation.java @@ -87,6 +87,10 @@ public class KLocation implements Cloneable { return this; } + public Vector getDirection() { + return MathUtils.getDirection(this); + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/src/main/java/dev/brighten/ac/utils/MathUtils.java b/src/main/java/dev/brighten/ac/utils/MathUtils.java index c8cfbd4..7aba2a1 100644 --- a/src/main/java/dev/brighten/ac/utils/MathUtils.java +++ b/src/main/java/dev/brighten/ac/utils/MathUtils.java @@ -24,6 +24,12 @@ public class MathUtils { return to.subtract(from).length(); } + public static int angularDistance(double alpha, double beta) { + while (alpha < 0) alpha += 360; + while (beta < 0) beta += 360; + double phi = Math.abs(beta - alpha) % 360; + return (int) (phi > 180 ? 360 - phi : phi); + } public static boolean playerMoved(Location from, Location to) { return playerMoved(from.toVector(), to.toVector()); } diff --git a/src/main/java/dev/brighten/ac/utils/world/CollisionBox.java b/src/main/java/dev/brighten/ac/utils/world/CollisionBox.java index 8826a82..09ed3c2 100644 --- a/src/main/java/dev/brighten/ac/utils/world/CollisionBox.java +++ b/src/main/java/dev/brighten/ac/utils/world/CollisionBox.java @@ -15,5 +15,7 @@ public interface CollisionBox { CollisionBox expand(double x, double y, double z); void draw(EnumParticle particle, Player... players); void downCast(List list); + List downCast(); + boolean isNull(); } \ No newline at end of file diff --git a/src/main/java/dev/brighten/ac/utils/world/types/ComplexCollisionBox.java b/src/main/java/dev/brighten/ac/utils/world/types/ComplexCollisionBox.java index f2b7325..c90f37c 100644 --- a/src/main/java/dev/brighten/ac/utils/world/types/ComplexCollisionBox.java +++ b/src/main/java/dev/brighten/ac/utils/world/types/ComplexCollisionBox.java @@ -70,6 +70,16 @@ public class ComplexCollisionBox implements CollisionBox { box.downCast(list); } + @Override + public List downCast() { + List list = new ArrayList<>(); + + for (CollisionBox box : boxes) { + box.downCast(list); + } + return list; + } + @Override public boolean isNull() { for(CollisionBox box : boxes) diff --git a/src/main/java/dev/brighten/ac/utils/world/types/DynamicCollisionBox.java b/src/main/java/dev/brighten/ac/utils/world/types/DynamicCollisionBox.java index c3601e1..c214da4 100644 --- a/src/main/java/dev/brighten/ac/utils/world/types/DynamicCollisionBox.java +++ b/src/main/java/dev/brighten/ac/utils/world/types/DynamicCollisionBox.java @@ -8,6 +8,7 @@ import dev.brighten.ac.utils.world.CollisionBox; import lombok.Setter; import org.bukkit.entity.Player; +import java.util.ArrayList; import java.util.List; public class DynamicCollisionBox implements CollisionBox { @@ -70,6 +71,15 @@ public class DynamicCollisionBox implements CollisionBox { box.fetch(version, player, block).offset(x,y,z).downCast(list); } + @Override + public List downCast() { + List boxes = new ArrayList<>(); + + box.fetch(version, player, block).offset(x,y,z).downCast(boxes); + + return boxes; + } + @Override public boolean isNull() { return box.fetch(version, player, block).isNull(); diff --git a/src/main/java/dev/brighten/ac/utils/world/types/NoCollisionBox.java b/src/main/java/dev/brighten/ac/utils/world/types/NoCollisionBox.java index be65d58..9aedc6a 100644 --- a/src/main/java/dev/brighten/ac/utils/world/types/NoCollisionBox.java +++ b/src/main/java/dev/brighten/ac/utils/world/types/NoCollisionBox.java @@ -4,6 +4,7 @@ import dev.brighten.ac.packet.wrapper.objects.EnumParticle; import dev.brighten.ac.utils.world.CollisionBox; import org.bukkit.entity.Player; +import java.util.Collections; import java.util.List; public class NoCollisionBox implements CollisionBox { @@ -45,6 +46,11 @@ public class NoCollisionBox implements CollisionBox { @Override public void downCast(List list) { /**/ } + @Override + public List downCast() { + return Collections.emptyList(); + } + @Override public boolean isNull() { return true; diff --git a/src/main/java/dev/brighten/ac/utils/world/types/RayCollision.java b/src/main/java/dev/brighten/ac/utils/world/types/RayCollision.java index 5f0825a..88c727c 100644 --- a/src/main/java/dev/brighten/ac/utils/world/types/RayCollision.java +++ b/src/main/java/dev/brighten/ac/utils/world/types/RayCollision.java @@ -20,6 +20,7 @@ import org.bukkit.util.Vector; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; public class RayCollision implements CollisionBox { @@ -211,6 +212,11 @@ public class RayCollision implements CollisionBox { @Override public void downCast(List list) {/*Do Nothing, Ray cannot be down-casted*/} + @Override + public List downCast() { + return Collections.emptyList(); + } + @Override public boolean isNull() { return true; diff --git a/src/main/java/dev/brighten/ac/utils/world/types/SimpleCollisionBox.java b/src/main/java/dev/brighten/ac/utils/world/types/SimpleCollisionBox.java index 3aeeec5..cb58c02 100644 --- a/src/main/java/dev/brighten/ac/utils/world/types/SimpleCollisionBox.java +++ b/src/main/java/dev/brighten/ac/utils/world/types/SimpleCollisionBox.java @@ -11,6 +11,7 @@ import org.bukkit.entity.Player; import org.bukkit.util.Vector; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Objects; @@ -134,6 +135,11 @@ public class SimpleCollisionBox implements CollisionBox { list.add(this); } + @Override + public List downCast() { + return Collections.singletonList(this); + } + @Override public boolean isNull() { return false;