From cda3b39870b59a5a487466b3df89fce8a3f2706e Mon Sep 17 00:00:00 2001 From: Dawson <30784509+funkemunky@users.noreply.github.com> Date: Tue, 1 Nov 2022 13:13:51 -0400 Subject: [PATCH] New checks and false positive fixes - Completed Autoclicker (C), Oscillation check. - Added Autoclicker (D). Checks for autoblocks - Added NoFall (C). Fall distance check. - Updated Phase setback to patch bypass. - Added PacketPlayOutMapChunk wrapper. - Tracking MapChunk updates to client, patches false positive from blocks not being updated on anticheat from plugins like FAWE. - Now sniffs packets that aren't wrapped too when packet debugging player. - Updated Fly (A) to now account for vertical collisions on predictions. - Added experimental flag to CheckData. - Removed lastFlagRun alert limiter. - Increased amount of alerts that can be displayed in a second from 40 to 80. --- pom.xml | 12 +- src/main/java/dev/brighten/ac/Anticheat.java | 2 +- .../java/dev/brighten/ac/check/Check.java | 41 ++-- .../java/dev/brighten/ac/check/CheckData.java | 1 + .../impl/combat/autoclicker/AutoclickerC.java | 65 +++++- .../impl/combat/autoclicker/AutoclickerD.java | 68 ++++++ .../ac/check/impl/movement/Phase.java | 36 ++-- .../ac/check/impl/movement/fly/FlyA.java | 38 +++- .../check/impl/movement/nofall/NoFallC.java | 53 +++++ .../check/impl/movement/speed/Horizontal.java | 2 +- .../brighten/ac/handler/PacketHandler.java | 17 +- .../ac/handler/block/BlockUpdateHandler.java | 36 +++- .../brighten/ac/logging/LoggerManager.java | 8 +- .../ac/packet/wrapper/PacketConverter.java | 2 + .../ac/packet/wrapper/PacketType.java | 2 + .../ac/packet/wrapper/impl/Processor_18.java | 198 +++++++++++++++++- .../java/dev/brighten/ac/utils/XMaterial.java | 3 - 17 files changed, 490 insertions(+), 94 deletions(-) create mode 100644 src/main/java/dev/brighten/ac/check/impl/combat/autoclicker/AutoclickerD.java create mode 100644 src/main/java/dev/brighten/ac/check/impl/movement/nofall/NoFallC.java diff --git a/pom.xml b/pom.xml index 0a5d000..23d31ef 100644 --- a/pom.xml +++ b/pom.xml @@ -42,6 +42,7 @@ 8 8 + true -XDignore.symbol.file @@ -63,7 +64,14 @@ shade - false + true + + + it.unimi.dsi + + dev.brighten.ac.utils.it.unimi.dsi + + @@ -112,7 +120,7 @@ it.unimi.dsi fastutil 8.5.6 - provided + compile com.shevchik.protocolsupport diff --git a/src/main/java/dev/brighten/ac/Anticheat.java b/src/main/java/dev/brighten/ac/Anticheat.java index 00e6299..857c589 100644 --- a/src/main/java/dev/brighten/ac/Anticheat.java +++ b/src/main/java/dev/brighten/ac/Anticheat.java @@ -46,7 +46,7 @@ import java.util.concurrent.atomic.AtomicLong; @Init //@MavenLibrary(groupId = "co.aikar", artifactId = "acf-bukkit", version = "0.5.1", repo = @Repository(url = "https://nexus.funkemunky.cc/content/repositories/releases/")) @MavenLibrary(groupId = "com.google.guava", artifactId = "guava", version = "21.0", repo = @Repository(url = "https://repo1.maven.org/maven2")) -@MavenLibrary(groupId = "it.unimi.dsi", artifactId = "fastutil", version = "8.5.6", repo = @Repository(url = "https://repo1.maven.org/maven2")) +//@MavenLibrary(groupId = "it.unimi.dsi", artifactId = "fastutil", version = "8.5.6", repo = @Repository(url = "https://repo1.maven.org/maven2")) @MavenLibrary(groupId = "org.ow2.asm", artifactId = "asm", version = "9.2", repo = @Repository(url = "https://repo1.maven.org/maven2")) @MavenLibrary(groupId = "org.ow2.asm", artifactId = "asm-tree", version = "9.2", repo = @Repository(url = "https://repo1.maven.org/maven2")) public class Anticheat extends LoaderPlugin { diff --git a/src/main/java/dev/brighten/ac/check/Check.java b/src/main/java/dev/brighten/ac/check/Check.java index 0fca4f2..e35c890 100644 --- a/src/main/java/dev/brighten/ac/check/Check.java +++ b/src/main/java/dev/brighten/ac/check/Check.java @@ -5,6 +5,7 @@ import dev.brighten.ac.api.AnticheatAPI; import dev.brighten.ac.api.check.CheckType; import dev.brighten.ac.api.check.ECheck; import dev.brighten.ac.api.event.AnticheatEvent; +import dev.brighten.ac.api.event.result.CancelResult; import dev.brighten.ac.api.event.result.FlagResult; import dev.brighten.ac.api.event.result.PunishResult; import dev.brighten.ac.data.APlayer; @@ -17,6 +18,7 @@ import lombok.val; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.chat.*; import org.bukkit.Bukkit; +import org.bukkit.Location; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; @@ -29,7 +31,6 @@ public class Check implements ECheck { private final CheckData checkData; @Getter public float vl; - private long lastFlagRun; @Getter @Setter private boolean enabled, punishable, cancellable; @@ -65,14 +66,6 @@ public class Check implements ECheck { .replace("%info%", info)); } - public void onEnable() { - - } - - public void onDisable() { - - } - private String addPlaceHolders(String string) { return string.replace("%player%", player.getBukkitPlayer().getName()) .replace("%check%", checkData.name()) @@ -83,7 +76,6 @@ public class Check implements ECheck { } public void cancel() { - /* CancelResult result = CancelResult.builder().cancelled(false).build(); for (AnticheatEvent event : AnticheatAPI.INSTANCE.getAllEvents()) { @@ -104,15 +96,15 @@ public class Check implements ECheck { .toLocation(player.getBukkitPlayer().getWorld()), 10); player.getBukkitPlayer().teleport(ground); - }*/ + } } public void debug(String information, Object... variables) { if(!Anticheat.allowDebug) return; - if(debugInstances.containsKey(checkData.name())) { - val list = debugInstances.get(checkData.name()); + val list = debugInstances.get(checkData.name()); + if(list != null) { for (Tuple tuple : list) { UUID toDebug = tuple.one; @@ -130,8 +122,14 @@ public class Check implements ECheck { } } - public Optional find(Class checkClass) { - return Optional.ofNullable((T) player.getCheckHandler().findCheck((Class) checkClass)); + public Optional find(Class checkClass) { + Check check = player.getCheckHandler().findCheck(checkClass); + + if(check != null) { + return Optional.of(checkClass.cast(check)); + } + + return Optional.empty(); } static List devComponents = new ArrayList<>(), components = new ArrayList<>(); @@ -160,8 +158,6 @@ public class Check implements ECheck { public void flag(boolean punish, String information, Object... variables) { vl++; - if(System.currentTimeMillis() - lastFlagRun < 50L) return; - lastFlagRun = System.currentTimeMillis(); Anticheat.INSTANCE.getScheduler().execute(() -> { if(Anticheat.INSTANCE.getTps() < 18) @@ -186,9 +182,7 @@ public class Check implements ECheck { alertCountReset.reset(); } - if(alertCount.incrementAndGet() < 40) { - boolean dev = Anticheat.INSTANCE.getTps() < 18; - + if(alertCount.incrementAndGet() < 80) { //Sending Discord webhook alert List toSend = new ArrayList<>(); @@ -245,11 +239,4 @@ public class Check implements ECheck { }); } } - - private TextComponent createTxt(String txt) { - return createTxt(txt, ""); - } - private TextComponent createTxt(String txt, String info) { - return new TextComponent(TextComponent.fromLegacyText(Color.translate(formatAlert(txt, info)))); - } } diff --git a/src/main/java/dev/brighten/ac/check/CheckData.java b/src/main/java/dev/brighten/ac/check/CheckData.java index 33f6980..2c162fc 100644 --- a/src/main/java/dev/brighten/ac/check/CheckData.java +++ b/src/main/java/dev/brighten/ac/check/CheckData.java @@ -15,6 +15,7 @@ public @interface CheckData { boolean enabled() default true; boolean punishable() default true; boolean cancellable() default true; + boolean experimental() default false; int punishVl() default 10; ProtocolVersion minVersion() default ProtocolVersion.V1_7; diff --git a/src/main/java/dev/brighten/ac/check/impl/combat/autoclicker/AutoclickerC.java b/src/main/java/dev/brighten/ac/check/impl/combat/autoclicker/AutoclickerC.java index 321a217..9f6c8ea 100644 --- a/src/main/java/dev/brighten/ac/check/impl/combat/autoclicker/AutoclickerC.java +++ b/src/main/java/dev/brighten/ac/check/impl/combat/autoclicker/AutoclickerC.java @@ -15,26 +15,71 @@ public class AutoclickerC extends Check { super(player); } - private int clicks; - private long lastArm, totalTime; + private long totalClickTime, lastClickTime; + private int clicks, oscillationTime, oscillationLevel, lowest, highest; @Async - WTimedAction action = (packet, now) -> { + WTimedAction action = (packet, timeStamp) -> { if(player.getInfo().isBreakingBlock()) return; - long delta = now - lastArm; clicks++; + long diff = timeStamp - lastClickTime; - totalTime+= delta; + if ((totalClickTime += diff) > 990) { - if(totalTime > 990) { - if(clicks >= 3 && delta <= 200) { + if (clicks >= 3 && diff <= 200.0f) { + int time = oscillationTime + 1; + int lowest = this.lowest; + int highest = this.highest; + + if (lowest == -1) { + lowest = clicks; + } else if (clicks < lowest) { + lowest = clicks; + } + if (highest == -1) { + highest = clicks; + } else if (clicks > highest) { + highest = clicks; + } + + int oscillation = highest - lowest; + int oscLevel = oscillationLevel; + if (time >= 9) { + if (highest >= 8) { + if (highest >= 9 && oscillation <= 5) { + oscLevel += 2; + } + if (oscillation > 3 && oscLevel > 0) { + --oscLevel; + } + } else if (oscLevel > 0) { + --oscLevel; + } + time = 0; + highest = -1; + lowest = -1; + } + if (oscillation > 2) { + time = 0; + oscLevel = 0; + highest = -1; + lowest = -1; + } + if (oscLevel >= 10) { + vl++; + flag("osc=" + oscLevel); + } + debug("osc=%s level=%s high=%s low=%s", oscillation, oscLevel, highest, lowest); + this.lowest = lowest; + this.highest = highest; + this.oscillationTime = time; + this.oscillationLevel = oscLevel; } + totalClickTime = 0; clicks = 1; - totalTime = 0; } - - lastArm = now; + lastClickTime = timeStamp; }; } diff --git a/src/main/java/dev/brighten/ac/check/impl/combat/autoclicker/AutoclickerD.java b/src/main/java/dev/brighten/ac/check/impl/combat/autoclicker/AutoclickerD.java new file mode 100644 index 0000000..d0b8fbb --- /dev/null +++ b/src/main/java/dev/brighten/ac/check/impl/combat/autoclicker/AutoclickerD.java @@ -0,0 +1,68 @@ +package dev.brighten.ac.check.impl.combat.autoclicker; + +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.WTimedAction; +import dev.brighten.ac.data.APlayer; +import dev.brighten.ac.packet.ProtocolVersion; +import dev.brighten.ac.packet.wrapper.in.WPacketPlayInArmAnimation; +import dev.brighten.ac.packet.wrapper.in.WPacketPlayInBlockPlace; +import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying; +import dev.brighten.ac.utils.math.cond.MaxDouble; +import org.bukkit.Material; + +import java.util.Arrays; +import java.util.EnumSet; + +@CheckData(name = "Autoclicker (D)", checkId = "autoclickerd", type = CheckType.AUTOCLICKER, punishVl = 15, + maxVersion = ProtocolVersion.V1_8_9) +public class AutoclickerD extends Check { + public AutoclickerD(APlayer player) { + super(player); + } + + private static final EnumSet SWORDS = EnumSet.allOf(Material.class); + + static { + Arrays.stream(Material.values()).filter(material -> material.name().contains("SWORD")) + .forEach(SWORDS::add); + } + + private long lastArm; + private double cps; + private boolean blocked; + private int armTicks; + private final MaxDouble verbose = new MaxDouble(40); + + WTimedAction animation = (packet, timeStamp) -> { + if(player.getInfo().isBreakingBlock()) return; + + cps = 1000D / (timeStamp - lastArm); + lastArm = timeStamp; + armTicks++; + }; + + WAction flying = packet -> { + if(blocked) { + if(armTicks > 0) { + if(armTicks == 1 && cps > 3) { + if(cps > 7) verbose.add(); + if(verbose.value() > 15) { + flag("arm=%s cps=%.3f lagging=%s", armTicks, + cps, player.getLagInfo()); + } + } else verbose.subtract(20); + debug("cps=%s arm=%s vb=%s", cps, armTicks, verbose.value()); + } + blocked = false; + armTicks = 0; + } + }; + + WAction place = packet -> { + if(packet.getItemStack() == null || !packet.getItemStack().getType().name().contains("SWORD")) return; + blocked = true; + }; +} diff --git a/src/main/java/dev/brighten/ac/check/impl/movement/Phase.java b/src/main/java/dev/brighten/ac/check/impl/movement/Phase.java index 56f27fc..c5cfda6 100644 --- a/src/main/java/dev/brighten/ac/check/impl/movement/Phase.java +++ b/src/main/java/dev/brighten/ac/check/impl/movement/Phase.java @@ -10,6 +10,7 @@ import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying; import dev.brighten.ac.packet.wrapper.out.WPacketPlayOutPosition; import dev.brighten.ac.utils.*; import dev.brighten.ac.utils.world.types.SimpleCollisionBox; +import org.bukkit.Location; import org.bukkit.util.Vector; import java.util.HashSet; @@ -24,9 +25,8 @@ public class Phase extends Check { } private int ticks; - private KLocation toSetback = null; - private Set positions = new HashSet<>(); + private Location teleportLoc = null; WAction positionOut = packet -> { KLocation loc = new KLocation(packet.getX(), packet.getY(), packet.getZ(), @@ -56,18 +56,6 @@ public class Phase extends Check { return false; } - if(toSetback != null && packet.isMoved()) { - if(player.getMovement().getTo().getLoc().distanceSquared(toSetback) < 1E-8) { - toSetback = null; - debug("Reached loc"); - } else { - RunUtils.task(() -> player.getBukkitPlayer().teleport(toSetback - .toLocation(player.getBukkitPlayer().getWorld()))); - debug("Hasnt reached location"); - return true; - } - } - if(!packet.isMoved() || player.getCreation().isNotPassed(800L) || player.getInfo().lastRespawn.isNotPassed(10) || player.getInfo().isCreative() || player.getInfo().isCanFly()) { @@ -78,11 +66,13 @@ public class Phase extends Check { .anyMatch(v -> v.distanceSquared(player.getMovement().getTo().getLoc().toVector()) < 0.0001)) { debug("Returned: [%s, %s, %s]", player.getMovement().getTo().getX(), player.getMovement().getTo().getY(), player.getMovement().getTo().getZ()); - debug("Locs:"); - positions.stream().forEach(v -> debug("loc: [%s, %s, %s]", v.getX(), v.getY(), v.getZ())); + teleportLoc = null; return false; } else if(player.getMovement().getMoveTicks() > 0 && player.getMovement().getTeleportsToConfirm() == 0) { positions.clear(); + } else if(teleportLoc != null) { + RunUtils.task(() -> player.getBukkitPlayer().teleport(teleportLoc)); + return true; } if(player.getMovement().getFrom().getLoc().distanceSquared(player.getMovement().getTo().getLoc()) > 400) { @@ -126,14 +116,12 @@ public class Phase extends Check { double totalDelta = dx + dy + dz; - if(totalDelta > 0.001) { - // Fixing calculated teleport location going wonky. If its 0.05 away, just set it to the from lOC. - if(calculatedTo.distanceSquared(player.getMovement().getFrom().getLoc()) > 0.0025) { - calculatedTo.setLocation(player.getMovement().getFrom().getLoc()); - } - - RunUtils.task(() -> player.getBukkitPlayer().teleport(calculatedTo - .toLocation(player.getBukkitPlayer().getWorld()))); + if(totalDelta > 0.00001) { + RunUtils.task(() -> { + teleportLoc = calculatedTo + .toLocation(player.getBukkitPlayer().getWorld()); + player.getBukkitPlayer().teleport(teleportLoc); + }); flag("x=%.4f, y=%.4f, z=%.4f", dx, dy, dz); } 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 bee88d8..551d8a4 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 @@ -7,22 +7,26 @@ import dev.brighten.ac.check.WAction; import dev.brighten.ac.data.APlayer; import dev.brighten.ac.packet.ProtocolVersion; import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying; +import dev.brighten.ac.utils.Helper; import dev.brighten.ac.utils.MathUtils; import dev.brighten.ac.utils.MovementUtils; import dev.brighten.ac.utils.annotation.Async; import dev.brighten.ac.utils.timer.Timer; import dev.brighten.ac.utils.timer.impl.MillisTimer; +import dev.brighten.ac.utils.world.types.SimpleCollisionBox; -@CheckData(name = "Fly (A)", checkId = "flya", type = CheckType.MOVEMENT) +import java.util.List; + +@CheckData(name = "Fly (A)", checkId = "flya", type = CheckType.MOVEMENT, experimental = true, punishVl = 7) public class FlyA extends Check { public FlyA(APlayer player) { super(player); } - private Timer lastPos = new MillisTimer(); + private final Timer lastPos = new MillisTimer(); private float buffer; - private static double mult = 0.98f, previousPrediction; + private static final double mult = 0.98f; private boolean didNextPrediction = false; @Async @@ -51,7 +55,6 @@ public class FlyA extends Check { if(Math.abs(player.getMovement().getDeltaY() - toCheck) < Math.abs(player.getMovement().getDeltaY() - predicted)) { - previousPrediction = predicted; predicted = toCheck; didNextPrediction = true; } @@ -65,11 +68,30 @@ public class FlyA extends Check { debug("Setting y to 0"); } + if(player.getBlockInfo().blocksBelow || player.getInfo().isNearGround()) { + List list = Helper.getCollisions(player, + player.getMovement().getFrom().getBox().copy().addCoord(player.getMovement().getDeltaX(), predicted, + player.getMovement().getDeltaZ())); + SimpleCollisionBox axisalignedbb4 = player.getMovement().getFrom().getBox(); + SimpleCollisionBox axisalignedbb5 = axisalignedbb4.copy().addCoord(player.getMovement().getDeltaX(), + 0.0D, player.getMovement().getDeltaZ()); + double d9 = predicted; + + for (SimpleCollisionBox axisalignedbb6 : list) { + d9 = axisalignedbb6.calculateYOffset(axisalignedbb5, d9); + } + + if(predicted != d9) { + debug("Collided!"); + } + + predicted = d9; + } + double deltaPredict = MathUtils.getDelta(player.getMovement().getDeltaY(), predicted); if(!player.getInfo().isGeneralCancel() && player.getMovement().getTeleportsToConfirm() == 0 - && player.getInfo().getBlockAbove().isPassed(1) && !player.getInfo().isOnLadder() && player.getInfo().climbTimer.isPassed(2) && !player.getBlockInfo().inWeb @@ -77,15 +99,13 @@ public class FlyA extends Check { && !player.getBlockInfo().inScaffolding && player.getInfo().getLastLiquid().isPassed(2) && !player.getBlockInfo().fenceBelow - && !packet.isOnGround() && player.getInfo().worldLoaded - && !player.getInfo().isServerGround() && !player.getBlockInfo().onHalfBlock && player.getInfo().getVelocity().isPassed(1) && !player.getBlockInfo().onSlime && deltaPredict > (player.getInfo().getClientAirTicks() < 3 ? 0.017 : 0.001)) { - if(++buffer > 3) { - buffer = 3; + if(++buffer > 1) { + buffer = 1; flag("dY=%.3f p=%.3f dx=%.3f", player.getMovement().getDeltaY(), predicted, player.getMovement().getDeltaXZ()); cancel(); diff --git a/src/main/java/dev/brighten/ac/check/impl/movement/nofall/NoFallC.java b/src/main/java/dev/brighten/ac/check/impl/movement/nofall/NoFallC.java new file mode 100644 index 0000000..aeaddd8 --- /dev/null +++ b/src/main/java/dev/brighten/ac/check/impl/movement/nofall/NoFallC.java @@ -0,0 +1,53 @@ +package dev.brighten.ac.check.impl.movement.nofall; + +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.WPacketPlayInFlying; +import dev.brighten.ac.utils.MathUtils; + +@CheckData(name = "NoFall (C)", checkId = "nofallc", type = CheckType.MOVEMENT, punishVl = 5, punishable = false, experimental = true) +public class NoFallC extends Check { + + public NoFallC(APlayer player) { + super(player); + } + + private double fallDistance, trueFallDistance; + + WAction flying = packet -> { + if(!packet.isMoved()) + return; + + if(player.getInfo().isGeneralCancel() || player.getMovement().getLastTeleport().isNotPassed(1)) { + fallDistance = trueFallDistance = 0; + return; + } + + if(player.getMovement().getDeltaY() > 0) { + fallDistance = 0; + trueFallDistance = 0; + } else { + if(packet.isOnGround()) { + fallDistance = 0; + } else fallDistance+= player.getMovement().getDeltaY(); + + if(player.getInfo().isServerGround()) { + trueFallDistance = 0; + fallDistance = 0; + } else trueFallDistance+= player.getMovement().getDeltaY(); + + double delta = MathUtils.getDelta(trueFallDistance, fallDistance); + + if(delta > 0.1) { + flag("delta=%.4f;fd=%.4f;tf=%.4f", delta, fallDistance, trueFallDistance); + fallDistance = trueFallDistance = 0; + cancel(); + } + + debug("calc=%.3f, true=%.3f", fallDistance, trueFallDistance); + } + }; +} 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 8e18f94..d19e164 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 @@ -22,7 +22,7 @@ import org.bukkit.util.Vector; import java.util.ArrayList; import java.util.List; -@CheckData(name = "Horizontal", checkId = "horizontala", type = CheckType.MOVEMENT) +@CheckData(name = "Horizontal", checkId = "horizontala", type = CheckType.MOVEMENT, experimental = true) public class Horizontal extends Check { private boolean lastLastClientGround; private float buffer; diff --git a/src/main/java/dev/brighten/ac/handler/PacketHandler.java b/src/main/java/dev/brighten/ac/handler/PacketHandler.java index e11644a..090d4a5 100644 --- a/src/main/java/dev/brighten/ac/handler/PacketHandler.java +++ b/src/main/java/dev/brighten/ac/handler/PacketHandler.java @@ -148,6 +148,12 @@ public class PacketHandler { player.getBlockUpdateHandler().runUpdate(packet); break; } + case MAP_CHUNK: { + WPacketPlayOutMapChunk packet = (WPacketPlayOutMapChunk) packetObject; + + player.getBlockUpdateHandler().runUpdate(packet); + break; + } case ENTITY_EFFECT: { WPacketPlayOutEntityEffect packet = (WPacketPlayOutEntityEffect) packetObject; @@ -334,9 +340,14 @@ public class PacketHandler { } } - if(player.sniffing && type != PacketType.UNKNOWN) { - player.sniffedPackets.add("[" + Anticheat.INSTANCE.getKeepaliveProcessor().tick + "] " + - "" + type.name() + ": " + packetObject.toString()); + if(player.sniffing) { + if(type != PacketType.UNKNOWN) { + player.sniffedPackets.add("[" + Anticheat.INSTANCE.getKeepaliveProcessor().tick + "] " + + "" + type.name() + ": " + packetObject.toString()); + } else { + player.sniffedPackets.add("[" + Anticheat.INSTANCE.getKeepaliveProcessor().tick + "] (UNKNOWN) " + + "" + packetObject.getClass().getSimpleName() + ": " + packetObject); + } } boolean cancelled = player.getCheckHandler().callSyncPacket(packetObject, timestamp); diff --git a/src/main/java/dev/brighten/ac/handler/block/BlockUpdateHandler.java b/src/main/java/dev/brighten/ac/handler/block/BlockUpdateHandler.java index 83bfa3b..1a02aa8 100644 --- a/src/main/java/dev/brighten/ac/handler/block/BlockUpdateHandler.java +++ b/src/main/java/dev/brighten/ac/handler/block/BlockUpdateHandler.java @@ -4,13 +4,14 @@ import dev.brighten.ac.data.APlayer; import dev.brighten.ac.packet.wrapper.in.WPacketPlayInBlockDig; import dev.brighten.ac.packet.wrapper.in.WPacketPlayInBlockPlace; import dev.brighten.ac.packet.wrapper.out.WPacketPlayOutBlockChange; +import dev.brighten.ac.packet.wrapper.out.WPacketPlayOutMapChunk; import dev.brighten.ac.packet.wrapper.out.WPacketPlayOutMultiBlockChange; import dev.brighten.ac.utils.BlockUtils; import dev.brighten.ac.utils.Materials; import dev.brighten.ac.utils.XMaterial; import dev.brighten.ac.utils.math.IntVector; import dev.brighten.ac.utils.world.types.RayCollision; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import lombok.RequiredArgsConstructor; import org.bukkit.Location; import org.bukkit.Material; @@ -21,7 +22,7 @@ import java.util.Optional; @RequiredArgsConstructor public class BlockUpdateHandler { - private final Int2ObjectOpenHashMap blockInformation = new Int2ObjectOpenHashMap<>(); + private final Object2ObjectOpenHashMap blockInformation = new Object2ObjectOpenHashMap<>(); private final APlayer player; @@ -62,7 +63,7 @@ public class BlockUpdateHandler { player.getInfo().getLastPlace().reset(); synchronized (blockInformation) { - blockInformation.put(pos.hashCode(), new WrappedBlock(pos.toLocation(player.getBukkitPlayer().getWorld()), + blockInformation.put(pos, new WrappedBlock(pos.toLocation(player.getBukkitPlayer().getWorld()), place.getItemStack().getType(), (byte) 0)); } } @@ -76,7 +77,7 @@ public class BlockUpdateHandler { player.getInfo().lastBlockUpdate.reset(); if (dig.getDigType() == WPacketPlayInBlockDig.EnumPlayerDigType.STOP_DESTROY_BLOCK) { synchronized (blockInformation) { - blockInformation.put(dig.getBlockPos().hashCode(), + blockInformation.put(dig.getBlockPos(), new WrappedBlock(dig.getBlockPos().toLocation(player.getBukkitPlayer().getWorld()), Material.AIR, (byte) 0)); } @@ -90,7 +91,7 @@ public class BlockUpdateHandler { // Updating block information player.runInstantAction(k -> { if (k.isEnd()) { - blockInformation.put(packet.getBlockLocation().hashCode(), + blockInformation.put(packet.getBlockLocation(), new WrappedBlock(packet.getBlockLocation().toLocation(player.getBukkitPlayer().getWorld()), packet.getMaterial(), packet.getBlockData())); } @@ -104,7 +105,10 @@ public class BlockUpdateHandler { if (k.isEnd()) { synchronized (blockInformation) { for (WPacketPlayOutMultiBlockChange.BlockChange info : packet.getChanges()) { - blockInformation.put(info.getLocation().hashCode(), + WrappedBlock block = new WrappedBlock(info.getLocation() + .toLocation(player.getBukkitPlayer().getWorld()), + info.getMaterial(), info.getData()); + blockInformation.put(info.getLocation(), new WrappedBlock(info.getLocation().toLocation(player.getBukkitPlayer().getWorld()), info.getMaterial(), info.getData())); } @@ -113,11 +117,23 @@ public class BlockUpdateHandler { }); } + public void runUpdate(WPacketPlayOutMapChunk chunkUpdate) { + player.runInstantAction(k -> { + if(!k.isEnd()) { + synchronized (blockInformation) { + chunkUpdate.getBlocks().forEach((vec, mblock) -> { + WrappedBlock block = new WrappedBlock(vec.toLocation(player.getBukkitPlayer().getWorld()), + mblock.material, mblock.data); + blockInformation.put(vec, block); + }); + } + } + }); + } + public WrappedBlock getBlock(IntVector loc) { synchronized (blockInformation) { - - final int hashCode = loc.hashCode(); - WrappedBlock block = blockInformation.get(hashCode); + WrappedBlock block = blockInformation.get(loc); if (block == null) { Optional bukkitBlock = BlockUtils.getBlockAsync( @@ -128,7 +144,7 @@ public class BlockUpdateHandler { IntVector intVec = new IntVector(bloc.getBlockX(), bloc.getBlockY(), bloc.getBlockZ()); block = new WrappedBlock(intVec.toLocation(player.getBukkitPlayer().getWorld()), bukkitBlock.get().getType(), bukkitBlock.get().getData()); - blockInformation.put(hashCode, block); + blockInformation.put(loc, block); } else block = new WrappedBlock(loc.toLocation(player.getBukkitPlayer().getWorld()), Material.AIR, (byte)0); } diff --git a/src/main/java/dev/brighten/ac/logging/LoggerManager.java b/src/main/java/dev/brighten/ac/logging/LoggerManager.java index f458f01..2a96699 100644 --- a/src/main/java/dev/brighten/ac/logging/LoggerManager.java +++ b/src/main/java/dev/brighten/ac/logging/LoggerManager.java @@ -14,7 +14,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Queue; import java.util.UUID; -import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Consumer; @@ -22,7 +22,7 @@ import java.util.function.Consumer; public class LoggerManager { - private final Queue logList = new LinkedBlockingQueue<>(); + private final Queue logList = new ConcurrentLinkedQueue<>(); private String license; /* @@ -53,7 +53,9 @@ public class LoggerManager { if(log != null) { oos.writeUTF(log.toJson()); - } else break; + } else if(logList.size() == 0) { + break; + } } System.out.println("Wrote " + i + " logs;" + logList.size()); 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 5b8375a..b3c0e46 100644 --- a/src/main/java/dev/brighten/ac/packet/wrapper/PacketConverter.java +++ b/src/main/java/dev/brighten/ac/packet/wrapper/PacketConverter.java @@ -86,4 +86,6 @@ public interface PacketConverter { WPacketPlayOutTransaction processServerTransaction(Object object); Object processServerTransaction(WPacketPlayOutTransaction packet); + + WPacketPlayOutMapChunk processMapChunk(Object object); } 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 ca026f6..56caa0e 100644 --- a/src/main/java/dev/brighten/ac/packet/wrapper/PacketType.java +++ b/src/main/java/dev/brighten/ac/packet/wrapper/PacketType.java @@ -148,6 +148,8 @@ public enum PacketType { return convert.processClientTransaction(object); case SERVER_TRANSACTION: return convert.processServerTransaction(object); + case MAP_CHUNK: + return convert.processMapChunk(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 8dd6c28..5049322 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 @@ -25,7 +25,10 @@ import org.bukkit.potion.PotionEffectType; import org.bukkit.util.Vector; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.stream.Collectors; public class Processor_18 implements PacketConverter { @@ -743,6 +746,199 @@ public class Processor_18 implements PacketConverter { return new PacketPlayOutTransaction(packet.getId(), packet.getAction(), packet.isAccept()); } + @Override + public WPacketPlayOutMapChunk processMapChunk(Object object) { + PacketPlayOutMapChunk packet = (PacketPlayOutMapChunk) object; + + PacketDataSerializer serialized = serialize(packet); + + int chunkX = serialized.readInt(); + int chunkZ = serialized.readInt(); + boolean groundUp = serialized.readBoolean(); + int size = serialized.readShort(); + byte[] locs = serialized.a(); + + ChunkSection[] sections = new ChunkSection[16]; + + //fillChunk(chunk, locs, size, groundUp); + int i = 0; + for (int index = 0; index < sections.length; ++index) { + if ((size & 1 << index) != 0) { + if (sections[index] == null) { + sections[index] = new ChunkSection(index << 4, true); + } + + char[] achar = sections[index].getIdArray(); + + for (int k = 0; k < achar.length; ++k) { + achar[k] = (char) ((locs[i + 1] & 255) << 8 | locs[i] & 255); + i += 2; + } + } else if (groundUp && sections[index] != null) { + sections[index] = null; + } + } + + + Map blocks = new HashMap<>(); + + int sectionIndex = 0; + for (ChunkSection section : sections) { + if(section == null) { + sectionIndex++; + continue; + } + for (int idIndex = 0; idIndex < section.getIdArray().length; idIndex++) { + //int i, int j, int k + // x, y, z + //j << 8 | k << 4 | i + int y = (section.getYPosition() + (idIndex >> 8)); + int z = (chunkZ * 16 + (idIndex >> 4 & 0xF)); + int x = (chunkX * 16 + (idIndex & 0xF)); + + char id = section.getIdArray()[idIndex]; + + IBlockData iblockdata = Block.d.a(id); + + Material material = CraftMagicNumbers.getMaterial(iblockdata.getBlock()); + + WPacketPlayOutMapChunk.MinBlock block = new WPacketPlayOutMapChunk + .MinBlock(material, (byte)iblockdata.getBlock().toLegacyData(iblockdata)); + + blocks.put(new IntVector(x, y, z), block); + } + sectionIndex++; + } + + return WPacketPlayOutMapChunk.builder().blocks(blocks).build(); + } + + public void fillChunk(Chunk chunk, byte[] p_177439_1_, int p_177439_2_, boolean p_177439_3_) { + int i = 0; + boolean flag = !chunk.getWorld().worldProvider.o(); + + for (int j = 0; j < chunk.getSections().length; ++j) { + if ((p_177439_2_ & 1 << j) != 0) { + if (chunk.getSections()[j] == null) { + chunk.getSections()[j] = new ChunkSection(j << 4, flag); + } + + char[] achar = chunk.getSections()[j].getIdArray(); + + for (int k = 0; k < achar.length; ++k) { + achar[k] = (char) ((p_177439_1_[i + 1] & 255) << 8 | p_177439_1_[i] & 255); + i += 2; + } + } else if (p_177439_3_ && chunk.getSections()[j] != null) { + chunk.getSections()[j] = null; + } + } + + if (p_177439_3_) { + System.arraycopy(p_177439_1_, i, chunk.getBiomeIndex(), 0, chunk.getBiomeIndex().length); + int k1 = i + chunk.getBiomeIndex().length; + } + + for (int j1 = 0; j1 < chunk.getSections().length; ++j1) { + if (chunk.getSections()[j1] != null && (p_177439_2_ & 1 << j1) != 0) { + chunk.getSections()[j1].recalcBlockCounts(); + } + } + + /*for (TileEntity tileentity : chunk.chunkTileEntityMap.values()) { + tileentity.updateContainingBlockInfo(); + }*/ + } + + /* + public void handleChunkData(S21PacketChunkData packetIn) { + PacketThreadUtil.checkThreadAndEnqueue(packetIn, this, this.gameController); + + if (packetIn.func_149274_i()) { + if (packetIn.getExtractedSize() == 0) { + this.clientWorldController.doPreChunk(packetIn.getChunkX(), packetIn.getChunkZ(), false); + return; + } + + this.clientWorldController.doPreChunk(packetIn.getChunkX(), packetIn.getChunkZ(), true); + } + + this.clientWorldController.invalidateBlockReceiveRegion(packetIn.getChunkX() << 4, 0, packetIn.getChunkZ() << 4, (packetIn.getChunkX() << 4) + 15, 256, (packetIn.getChunkZ() << 4) + 15); + Chunk chunk = this.clientWorldController.getChunkFromChunkCoords(packetIn.getChunkX(), packetIn.getChunkZ()); + chunk.fillChunk(packetIn.func_149272_d(), packetIn.getExtractedSize(), packetIn.func_149274_i()); + this.clientWorldController.markBlockRangeForRenderUpdate(packetIn.getChunkX() << 4, 0, packetIn.getChunkZ() << 4, (packetIn.getChunkX() << 4) + 15, 256, (packetIn.getChunkZ() << 4) + 15); + + if (!packetIn.func_149274_i() || !(this.clientWorldController.provider instanceof WorldProviderSurface)) { + chunk.resetRelightChecks(); + } + } + */ + /* + public void fillChunk(byte[] p_177439_1_, int p_177439_2_, boolean p_177439_3_) { + int i = 0; + boolean flag = !this.worldObj.provider.getHasNoSky(); + + for (int j = 0; j < this.storageArrays.length; ++j) { + if ((p_177439_2_ & 1 << j) != 0) { + if (this.storageArrays[j] == null) { + this.storageArrays[j] = new ExtendedBlockStorage(j << 4, flag); + } + + char[] achar = this.storageArrays[j].getData(); + + for (int k = 0; k < achar.length; ++k) { + achar[k] = (char) ((p_177439_1_[i + 1] & 255) << 8 | p_177439_1_[i] & 255); + i += 2; + } + } else if (p_177439_3_ && this.storageArrays[j] != null) { + this.storageArrays[j] = null; + } + } + + for (int l = 0; l < this.storageArrays.length; ++l) { + if ((p_177439_2_ & 1 << l) != 0 && this.storageArrays[l] != null) { + NibbleArray nibblearray = this.storageArrays[l].getBlocklightArray(); + System.arraycopy(p_177439_1_, i, nibblearray.getData(), 0, nibblearray.getData().length); + i += nibblearray.getData().length; + } + } + + if (flag) { + for (int i1 = 0; i1 < this.storageArrays.length; ++i1) { + if ((p_177439_2_ & 1 << i1) != 0 && this.storageArrays[i1] != null) { + NibbleArray nibblearray1 = this.storageArrays[i1].getSkylightArray(); + System.arraycopy(p_177439_1_, i, nibblearray1.getData(), 0, nibblearray1.getData().length); + i += nibblearray1.getData().length; + } + } + } + + if (p_177439_3_) { + System.arraycopy(p_177439_1_, i, this.blockBiomeArray, 0, this.blockBiomeArray.length); + int k1 = i + this.blockBiomeArray.length; + } + + for (int j1 = 0; j1 < this.storageArrays.length; ++j1) { + if (this.storageArrays[j1] != null && (p_177439_2_ & 1 << j1) != 0) { + this.storageArrays[j1].removeInvalidBlocks(); + } + } + + this.isLightPopulated = true; + this.isTerrainPopulated = true; + this.generateHeightMap(); + + for (TileEntity tileentity : this.chunkTileEntityMap.values()) { + tileentity.updateContainingBlockInfo(); + } + } + */ + + private static int a(byte[] abyte, byte[] abyte1, int i) { + System.arraycopy(abyte, 0, abyte1, i, abyte.length); + return i + abyte.length; + } + private PacketDataSerializer serialize(Packet packet) { PacketDataSerializer serial = new PacketDataSerializer(Unpooled.buffer()); try { diff --git a/src/main/java/dev/brighten/ac/utils/XMaterial.java b/src/main/java/dev/brighten/ac/utils/XMaterial.java index fe461b3..cb9ce27 100644 --- a/src/main/java/dev/brighten/ac/utils/XMaterial.java +++ b/src/main/java/dev/brighten/ac/utils/XMaterial.java @@ -1735,7 +1735,6 @@ public enum XMaterial { * @since 2.0.0 */ @Nonnull - @SuppressWarnings("deprecation") public static XMaterial matchXMaterial(@Nonnull ItemStack item) { Objects.requireNonNull(item, "Cannot match null ItemStack"); String material = item.getType().name(); @@ -2011,7 +2010,6 @@ public enum XMaterial { * @since 3.0.0 */ @Nonnull - @SuppressWarnings("deprecation") public ItemStack setType(@Nonnull ItemStack item) { Objects.requireNonNull(item, "Cannot set material for null ItemStack"); Material material = this.parseMaterial(); @@ -2090,7 +2088,6 @@ public enum XMaterial { * @return data of this material, or 0 if none. * @since 1.0.0 */ - @SuppressWarnings("deprecation") public byte getData() { return data; }