diff --git a/src/main/java/dev/brighten/ac/Anticheat.java b/src/main/java/dev/brighten/ac/Anticheat.java index 616f491..cdb2c88 100644 --- a/src/main/java/dev/brighten/ac/Anticheat.java +++ b/src/main/java/dev/brighten/ac/Anticheat.java @@ -58,6 +58,8 @@ public class Anticheat extends JavaPlugin { private RollingAverageDouble tps = new RollingAverageDouble(4, 20); private final Map worldInfoMap = new HashMap<>(); + public static boolean allowDebug = true; + @ConfigSetting(path = "logging", name = "verbose") private static boolean verboseLogging = true; diff --git a/src/main/java/dev/brighten/ac/check/Check.java b/src/main/java/dev/brighten/ac/check/Check.java index 137cf7c..f5137db 100644 --- a/src/main/java/dev/brighten/ac/check/Check.java +++ b/src/main/java/dev/brighten/ac/check/Check.java @@ -5,10 +5,14 @@ import dev.brighten.ac.data.APlayer; import dev.brighten.ac.utils.Color; import dev.brighten.ac.utils.MathUtils; import dev.brighten.ac.utils.MiscUtils; +import dev.brighten.ac.utils.Tuple; import dev.brighten.ac.utils.timer.Timer; import dev.brighten.ac.utils.timer.impl.MillisTimer; import lombok.Getter; import lombok.val; +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.ComponentBuilder; import net.md_5.bungee.api.chat.HoverEvent; import net.md_5.bungee.api.chat.TextComponent; @@ -26,7 +30,7 @@ public abstract class Check { public static List alertsEnabled = new ArrayList<>(); - public static final Map> debugInstances = new HashMap<>(); + public static final Map>> debugInstances = new HashMap<>(); public Check(APlayer player) { this.player = player; @@ -48,7 +52,25 @@ public abstract class Check { } public void debug(String information, Object... variables) { + if(!Anticheat.allowDebug) return; + if(debugInstances.containsKey(checkData.name())) { + val list = debugInstances.get(checkData.name()); + + for (Tuple tuple : list) { + UUID toDebug = tuple.one; + + if(!toDebug.equals(player.getUuid())) continue; + + ComponentBuilder builder = new ComponentBuilder("[DEBUG] ").color(ChatColor.RED); + + BaseComponent[] message = + builder.append(String.format(information, variables)).color(ChatColor.GRAY).create(); + + Anticheat.INSTANCE.getPlayerRegistry().getPlayer(tuple.two) + .ifPresent(player -> player.getBukkitPlayer().spigot().sendMessage(message)); + } + } } public void flag(String information, Object... variables) { diff --git a/src/main/java/dev/brighten/ac/check/CheckManager.java b/src/main/java/dev/brighten/ac/check/CheckManager.java index abefe84..56edc20 100644 --- a/src/main/java/dev/brighten/ac/check/CheckManager.java +++ b/src/main/java/dev/brighten/ac/check/CheckManager.java @@ -55,4 +55,10 @@ public class CheckManager { checkClasses.add(check); } + + public boolean isCheck(String name) { + final String formattedName = name.replace("_", " "); + return checkClasses.stream().anyMatch(c -> c.getCheckClass().getAnnotation(CheckData.class).name() + .equalsIgnoreCase(formattedName)); + } } diff --git a/src/main/java/dev/brighten/ac/check/impl/combat/Aim.java b/src/main/java/dev/brighten/ac/check/impl/combat/Aim.java index c9922a6..0c35e72 100644 --- a/src/main/java/dev/brighten/ac/check/impl/combat/Aim.java +++ b/src/main/java/dev/brighten/ac/check/impl/combat/Aim.java @@ -24,33 +24,22 @@ public class Aim extends Check { public void flying(WPacketPlayInFlying packet) { if(!packet.isLooked()) return; - final float sens = getPlayer().getMovement().getSensitivityMcp(), - deltaYaw = Math.abs(getPlayer().getMovement().getDeltaYaw()), - deltaPitch = Math.abs(getPlayer().getMovement().getDeltaPitch()); - final float deltaX = deltaYaw / getPlayer().getMovement().getYawMode(); - final float deltaY = deltaPitch / getPlayer().getMovement().getPitchMode(); - - if(getPlayer().getMovement().getYawGcdList().size() < 40) - return; - - final double gridX = getGrid(getPlayer().getMovement().getYawGcdList()), - gridY = getGrid(getPlayer().getMovement().getPitchGcdList()); - - if(gridX < 0.005 || gridY < 0.005) lastGrid.reset(); - - if(deltaX > 200 || deltaY > 200) { + if(getPlayer().getMovement().getYawGcdList().size() < 40 + || getPlayer().getMovement().getLookX() > 200 || getPlayer().getMovement().getLookY() > 200) { if(buffer > 0) buffer--; return; } if(getPlayer().getMovement().getPitchGCD() < 0.007 - && lastGrid.isPassed() - && getPlayer().getMovement().getLastHighRate().isNotPassed(3)) { - if(deltaPitch < 10 && ++buffer > 8) { - flag("%s", getPlayer().getMovement().getPitchGCD()); + && !getPlayer().getMovement().isCinematic()) { + if(Math.abs(getPlayer().getMovement().getDeltaPitch()) < 10 && ++buffer > 4) { + flag("gcd=%.5f", getPlayer().getMovement().getPitchGCD()); } - getPlayer().getBukkitPlayer().sendMessage("Flagged b:" + buffer); } else buffer = 0; + + debug("b=%s gcd=%.4f cin=%s", buffer, getPlayer().getMovement().getPitchGCD(), + getPlayer().getMovement().isCinematic()); + } /* diff --git a/src/main/java/dev/brighten/ac/check/impl/fly/FlyA.java b/src/main/java/dev/brighten/ac/check/impl/fly/FlyA.java index 99c7ba1..ad6852f 100644 --- a/src/main/java/dev/brighten/ac/check/impl/fly/FlyA.java +++ b/src/main/java/dev/brighten/ac/check/impl/fly/FlyA.java @@ -26,10 +26,11 @@ public class FlyA extends Check { @Action public void onFlying(WPacketPlayInFlying packet) { if(!packet.isMoved() || (getPlayer().getMovement().getDeltaXZ() == 0 - && getPlayer().getMovement().getDeltaY() == 0)) + && getPlayer().getMovement().getDeltaY() == 0)) { return; + } - boolean onGround = getPlayer().getMovement().getTo().isOnGround(), + boolean onGround = getPlayer().getMovement().getTo().isOnGround() && getPlayer().getBlockInformation().blocksBelow, fromGround = getPlayer().getMovement().getFrom().isOnGround(); double lDeltaY = fromGround ? 0 : getPlayer().getMovement().getLDeltaY(); double predicted = onGround ? lDeltaY : (lDeltaY - 0.08) * mult; @@ -53,7 +54,10 @@ public class FlyA extends Check { double deltaPredict = MathUtils.getDelta(getPlayer().getMovement().getDeltaY(), predicted); - if(!getPlayer().getInfo().isGeneralCancel() && deltaPredict > 0.016) { + if(!getPlayer().getInfo().isGeneralCancel() + && getPlayer().getInfo().getBlockAbove().isPassed(1) + && !getPlayer().getInfo().isOnLadder() + && !getPlayer().getBlockInformation().onSlime && deltaPredict > 0.016) { if(++buffer > 5) { buffer = 5; flag("dY=%.3f p=%.3f dx=%.3f", getPlayer().getMovement().getDeltaY(), predicted, diff --git a/src/main/java/dev/brighten/ac/check/impl/velocity/VelocityA.java b/src/main/java/dev/brighten/ac/check/impl/velocity/VelocityA.java new file mode 100644 index 0000000..398ef43 --- /dev/null +++ b/src/main/java/dev/brighten/ac/check/impl/velocity/VelocityA.java @@ -0,0 +1,57 @@ +package dev.brighten.ac.check.impl.velocity; + +import dev.brighten.ac.check.Action; +import dev.brighten.ac.check.Check; +import dev.brighten.ac.check.CheckData; +import dev.brighten.ac.check.CheckType; +import dev.brighten.ac.data.APlayer; +import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying; +import org.bukkit.util.Vector; + +@CheckData(name = "Velocity (A)", type = CheckType.MOVEMENT) +public class VelocityA extends Check { + + private Vector currentVelocity = null; + private float buffer = 0; + + public VelocityA(APlayer player) { + super(player); + + player.onVelocity(velocity -> { + + currentVelocity = velocity.clone(); + debug("did velocity: " + currentVelocity.getY()); + }); + } + + @Action + public void onFlying(WPacketPlayInFlying packet) { + if(currentVelocity != null && currentVelocity.getY() > 0 + && !getPlayer().getBlockInformation().inWeb + && !getPlayer().getBlockInformation().onClimbable + && getPlayer().getInfo().getBlockAbove().isPassed(6) + && !getPlayer().getBlockInformation().onSlime + && !getPlayer().getInfo().isGeneralCancel()) { + double pct = getPlayer().getMovement().getDeltaY() / currentVelocity.getY() * 100; + + if(pct < 99.999 || pct > 400) { + if(++buffer > 15) { + flag("pct=%.1f%% buffer=%.1f", pct, buffer); + } + } else if(buffer > 0) buffer-= 0.5; + + debug("pct=%.1f%% buffer=%.1f dy=%.4f vy=%.4f", pct, buffer, + getPlayer().getMovement().getDeltaY(), currentVelocity.getY()); + + currentVelocity.setY((currentVelocity.getY() - 0.08) * 0.98); + + if(currentVelocity.getY() < 0.005 + || getPlayer().getBlockInformation().collidesHorizontally + || getPlayer().getBlockInformation().collidesVertically + || getPlayer().getInfo().getVelocity().isPassed(7)) + currentVelocity = null; + } else if(currentVelocity != null) { + debug("not null: " + currentVelocity.getY()); + } + } +} diff --git a/src/main/java/dev/brighten/ac/command/AnticheatCommand.java b/src/main/java/dev/brighten/ac/command/AnticheatCommand.java index 606fe1f..30c6fc2 100644 --- a/src/main/java/dev/brighten/ac/command/AnticheatCommand.java +++ b/src/main/java/dev/brighten/ac/command/AnticheatCommand.java @@ -8,16 +8,17 @@ import dev.brighten.ac.check.CheckData; import dev.brighten.ac.data.APlayer; import dev.brighten.ac.messages.Messages; import dev.brighten.ac.packet.handler.HandlerAbstract; -import dev.brighten.ac.utils.Color; -import dev.brighten.ac.utils.Init; -import dev.brighten.ac.utils.MiscUtils; -import dev.brighten.ac.utils.Priority; +import dev.brighten.ac.utils.*; +import dev.brighten.ac.utils.msg.ChatBuilder; import io.netty.buffer.Unpooled; +import lombok.val; import net.minecraft.server.v1_8_R3.PacketDataSerializer; import net.minecraft.server.v1_8_R3.PacketPlayOutCustomPayload; +import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import java.util.ArrayList; import java.util.Comparator; import java.util.stream.Collectors; @@ -31,7 +32,7 @@ public class AnticheatCommand extends BaseCommand { .getCommandCompletions(); cc.registerCompletion("checks", (c) -> Anticheat.INSTANCE.getCheckManager().getCheckClasses().stream() - .map(cs -> cs.getCheckClass().getAnnotation(CheckData.class).name()) + .map(cs -> cs.getCheckClass().getAnnotation(CheckData.class).name().replace(" ", "_")) .sorted(Comparator.naturalOrder()).collect(Collectors.toList())); BukkitCommandContexts contexts = (BukkitCommandContexts) Anticheat.INSTANCE.getCommandManager() @@ -48,6 +49,29 @@ public class AnticheatCommand extends BaseCommand { + "Argument \"%s\" is not an integer", arg)); } }); + + contexts.registerOptionalContext(APlayer.class, c -> { + if(c.hasFlag("other")) { + String arg = c.popFirstArg(); + + Player onlinePlayer = Bukkit.getPlayer(arg); + + if(onlinePlayer != null) { + return Anticheat.INSTANCE.getPlayerRegistry().getPlayer(onlinePlayer.getUniqueId()) + .orElse(null); + } else return null; + } else { + CommandSender sender = c.getSender(); + + if(sender instanceof Player) { + return Anticheat.INSTANCE.getPlayerRegistry().getPlayer(((Player) sender).getUniqueId()) + .orElse(null); + } + else if(!c.isOptional()) throw new InvalidCommandArgument(MessageKeys.NOT_ALLOWED_ON_CONSOLE, + false, new String[0]); + else return null; + } + }); } @HelpCommand @@ -84,9 +108,8 @@ public class AnticheatCommand extends BaseCommand { @Syntax("[player]") @CommandCompletion("@players") @CommandPermission("anticheat.command.info") - public void onCommand(CommandSender sender, @Single Player target) { + public void onCommand(CommandSender sender, @Single APlayer player) { Anticheat.INSTANCE.getScheduler().execute(() -> { - APlayer player = Anticheat.INSTANCE.getPlayerRegistry().getPlayer(target.getUniqueId()).orElse(null); if(player == null) { sender.spigot().sendMessage(Messages.NULL_APLAYER); @@ -119,4 +142,50 @@ public class AnticheatCommand extends BaseCommand { }); }); } + + @Subcommand("debug") + @CommandCompletion("@checks|none @players") + @Description("Debug a player") + @CommandPermission("anticheat.command.debug") + public void onDebug(APlayer sender, @Single String check, @Optional APlayer targetPlayer) { + APlayer target = targetPlayer != null ? targetPlayer : sender; + if(check.equals("none")) { + synchronized (Check.debugInstances) { + Check.debugInstances.forEach((nameKey, list) -> { + val iterator = list.iterator(); + while(iterator.hasNext()) { + val tuple = iterator.next(); + + if(tuple.one.equals(target.getUuid())) { + iterator.remove(); + sender.getBukkitPlayer().spigot() + .sendMessage(new ChatBuilder( + "&cTurned off debug for check &f%s &con target &f%s", nameKey, + target.getBukkitPlayer().getName()).build()); + } + } + }); + } + } else { + if(!Anticheat.INSTANCE.getCheckManager().isCheck(check)) { + sender.getBukkitPlayer().sendMessage(Color.Red + "Check \"" + check + "\" is not a valid check!"); + return; + } + synchronized (Check.debugInstances) { + Check.debugInstances.compute(check.replace("_", " "), (key, list) -> { + if(list == null) list = new ArrayList<>(); + + list.add(new Tuple<>(target.getUuid(), sender.getUuid())); + + return list; + }); + + sender.getBukkitPlayer().spigot() + .sendMessage(new ChatBuilder( + "&aTurned on debug for check &f%s &con target &f%s", + check.replace("_", " "), + target.getBukkitPlayer().getName()).build()); + } + } + } } diff --git a/src/main/java/dev/brighten/ac/data/APlayer.java b/src/main/java/dev/brighten/ac/data/APlayer.java index 42b2d11..ec64bd3 100644 --- a/src/main/java/dev/brighten/ac/data/APlayer.java +++ b/src/main/java/dev/brighten/ac/data/APlayer.java @@ -28,6 +28,7 @@ import lombok.val; import net.minecraft.server.v1_8_R3.PacketPlayOutTransaction; import org.bukkit.entity.Player; import org.bukkit.event.Event; +import org.bukkit.util.Vector; import java.util.*; import java.util.concurrent.ThreadLocalRandom; @@ -71,6 +72,8 @@ public class APlayer { @Getter private final Deque packetQueue = new LinkedList<>(); + @Getter + private final List> onVelocityTasks = new ArrayList<>(); @Setter @Getter @@ -157,6 +160,10 @@ public class APlayer { return id; } + public void onVelocity(Consumer runnable) { + onVelocityTasks.add(runnable); + } + public void runInstantAction(Consumer runnable) { runInstantAction(runnable, false); @@ -192,4 +199,17 @@ public class APlayer { public void addPlayerTick() { playerTick++; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + APlayer aPlayer = (APlayer) o; + return Objects.equals(uuid, aPlayer.uuid); + } + + @Override + public int hashCode() { + return Objects.hash(uuid); + } } diff --git a/src/main/java/dev/brighten/ac/data/handlers/BlockInformation.java b/src/main/java/dev/brighten/ac/data/handlers/BlockInformation.java index 33b1224..7269b3d 100644 --- a/src/main/java/dev/brighten/ac/data/handlers/BlockInformation.java +++ b/src/main/java/dev/brighten/ac/data/handlers/BlockInformation.java @@ -4,6 +4,7 @@ import dev.brighten.ac.Anticheat; import dev.brighten.ac.data.APlayer; import dev.brighten.ac.packet.ProtocolVersion; import dev.brighten.ac.utils.*; +import dev.brighten.ac.utils.math.IntVector; import dev.brighten.ac.utils.world.BlockData; import dev.brighten.ac.utils.world.CollisionBox; import dev.brighten.ac.utils.world.EntityData; @@ -15,10 +16,7 @@ import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Entity; -import java.util.ArrayList; -import java.util.Collections; -import java.util.EnumMap; -import java.util.List; +import java.util.*; public class BlockInformation { private APlayer player; @@ -138,183 +136,186 @@ public class BlockInformation { break start; } if(y > 400 || y < -50) continue; - Block block = chunk.getBlock(x & 15, y, z & 15); - final Material type = block.getType(); - if (type != Material.AIR) { - blocks.add(block); + final Deque types = + player.getBlockUpdateHandler().getPossibleMaterials(new IntVector(x, y, z)); - CollisionBox blockBox = BlockData.getData(type) - .getBox(block, player.getPlayerVersion()); + for (Material type : types) { + if (type != Material.AIR) { + BlockUtils.getBlockAsync(new Location(world, x, y, z)).ifPresent(blocks::add); - if(blockBox.isCollided(normalBox)) { - if(type.equals(cobweb)) - inWeb = true; - else if(type.equals(scaffolding)) inScaffolding = true; - else if(type.equals(honey)) inHoney = true; - } + CollisionBox blockBox = BlockData.getData(type) + .getBox(world, new IntVector(x, y, z), player.getPlayerVersion()); - if(type.equals(rosebush)) - roseBush = true; - - if(normalBox.copy().offset(0, 0.6f, 0).isCollided(blockBox)) - blocksAbove = true; - - if(normalBox.copy().expand(1, -0.0001, 1).isIntersected(blockBox)) - blocksNear = true; - - if(normalBox.copy().expand(0.1, 0, 0.1) - .offset(0, 1,0).isCollided(blockBox)) { - synchronized (aboveCollisions) { - blockBox.downCast(aboveCollisions); - } - } - - if(normalBox.copy().expand(0.1, 0, 0.1).offset(0, -1, 0) - .isCollided(blockBox)) { - synchronized (belowCollisions) { - blockBox.downCast(belowCollisions); + if(blockBox.isCollided(normalBox)) { + if(type.equals(cobweb)) + inWeb = true; + else if(type.equals(scaffolding)) inScaffolding = true; + else if(type.equals(honey)) inHoney = true; } - if(Materials.checkFlag(type, Materials.FENCE) - || Materials.checkFlag(type, Materials.WALL)) { - fenceBelow = true; - } - } + if(type.equals(rosebush)) + roseBush = true; - if(Materials.checkFlag(type, Materials.SOLID)) { - SimpleCollisionBox groundBox = normalBox.copy() - .offset(0, -.49, 0).expandMax(0, -1.2, 0); + if(normalBox.copy().offset(0, 0.6f, 0).isCollided(blockBox)) + blocksAbove = true; - XMaterial blockMaterial = getXMaterial(type); + if(normalBox.copy().expand(1, -0.0001, 1).isIntersected(blockBox)) + blocksNear = true; - if(normalBox.copy().expand(0.4, 0, 0.4).expandMin(0, -1, 0) - .isIntersected(blockBox)) - blocksBelow = true; - - if(normalBox.isIntersected(blockBox)) inBlock = true; - - SimpleCollisionBox box = player.getMovement().getTo().getBox().copy(); - - box.expand(Math.abs(player.getMovement().getDeltaX()) + 0.1, -0.001, - Math.abs(player.getMovement().getDeltaZ()) + 0.1); - if (blockBox.isCollided(box)) - collidesHorizontally = true; - - box = player.getMovement().getTo().getBox().copy(); - box.expand(0, 0.1, 0); - - if (blockBox.isCollided(box)) - collidesVertically = true; - - if(groundBox.copy().expandMin(0, -0.8, 0).expand(0.2, 0, 0.2) - .isIntersected(blockBox)) - player.getInfo().setNearGround(true); - - if(groundBox.isCollided(blockBox)) { - player.getInfo().setServerGround(true); - - if(blockMaterial != null) - switch (blockMaterial) { - case ICE: - case BLUE_ICE: - case FROSTED_ICE: - case PACKED_ICE: { - onIce = true; - break; - } - case SOUL_SAND: { - onSoulSand = true; - break; - } - case SLIME_BLOCK: { - onSlime = true; - break; - } + if(normalBox.copy().expand(0.1, 0, 0.1) + .offset(0, 1,0).isCollided(blockBox)) { + synchronized (aboveCollisions) { + blockBox.downCast(aboveCollisions); } } - if(player.getMovement().getDeltaY() > 0 - && player.getPlayerVersion().isBelow(ProtocolVersion.V1_14) - && Materials.checkFlag(type, Materials.LADDER) - && normalBox.copy().expand(0.2f, 0, 0.2f) + + if(normalBox.copy().expand(0.1, 0, 0.1).offset(0, -1, 0) .isCollided(blockBox)) { - onClimbable = true; - } + synchronized (belowCollisions) { + blockBox.downCast(belowCollisions); + } - if(blockMaterial != null) { - switch (blockMaterial) { - case PISTON: - case PISTON_HEAD: - case MOVING_PISTON: - case STICKY_PISTON: { - if(normalBox.copy().expand(0.5, 0.5, 0.5) - .isCollided(blockBox)) - pistonNear = true; - break; - } + if(Materials.checkFlag(type, Materials.FENCE) + || Materials.checkFlag(type, Materials.WALL)) { + fenceBelow = true; } } - if(groundBox.copy().expand(0.5, 0.3, 0.5).isCollided(blockBox)) { - if(Materials.checkFlag(type, Materials.SLABS)) - onSlab = true; - else - if(Materials.checkFlag(type, Materials.STAIRS)) - onStairs = true; - else + if(Materials.checkFlag(type, Materials.SOLID)) { + SimpleCollisionBox groundBox = normalBox.copy() + .offset(0, -.49, 0).expandMax(0, -1.2, 0); + + XMaterial blockMaterial = getXMaterial(type); + + if(normalBox.copy().expand(0.4, 0, 0.4).expandMin(0, -1, 0) + .isIntersected(blockBox)) + blocksBelow = true; + + if(normalBox.isIntersected(blockBox)) inBlock = true; + + SimpleCollisionBox box = player.getMovement().getTo().getBox().copy(); + + box.expand(Math.abs(player.getMovement().getDeltaX()) + 0.1, -0.001, + Math.abs(player.getMovement().getDeltaZ()) + 0.1); + if (blockBox.isCollided(box)) + collidesHorizontally = true; + + box = player.getMovement().getTo().getBox().copy(); + box.expand(0, 0.1, 0); + + if (blockBox.isCollided(box)) + collidesVertically = true; + + if(groundBox.copy().expandMin(0, -0.8, 0).expand(0.2, 0, 0.2) + .isIntersected(blockBox)) + player.getInfo().setNearGround(true); + + if(groundBox.isCollided(blockBox)) { + player.getInfo().setServerGround(true); + + if(blockMaterial != null) + switch (blockMaterial) { + case ICE: + case BLUE_ICE: + case FROSTED_ICE: + case PACKED_ICE: { + onIce = true; + break; + } + case SOUL_SAND: { + onSoulSand = true; + break; + } + case SLIME_BLOCK: { + onSlime = true; + break; + } + } + } + if(player.getMovement().getDeltaY() > 0 + && player.getPlayerVersion().isBelow(ProtocolVersion.V1_14) + && Materials.checkFlag(type, Materials.LADDER) + && normalBox.copy().expand(0.2f, 0, 0.2f) + .isCollided(blockBox)) { + onClimbable = true; + } + + if(blockMaterial != null) { + switch (blockMaterial) { + case PISTON: + case PISTON_HEAD: + case MOVING_PISTON: + case STICKY_PISTON: { + if(normalBox.copy().expand(0.5, 0.5, 0.5) + .isCollided(blockBox)) + pistonNear = true; + break; + } + } + } + + if(groundBox.copy().expand(0.5, 0.3, 0.5).isCollided(blockBox)) { + if(Materials.checkFlag(type, Materials.SLABS)) + onSlab = true; + else + if(Materials.checkFlag(type, Materials.STAIRS)) + onStairs = true; + else + if(blockMaterial != null) + switch(blockMaterial) { + case CAKE: + case BREWING_STAND: + case FLOWER_POT: + case PLAYER_HEAD: + case PLAYER_WALL_HEAD: + case SKELETON_SKULL: + case CREEPER_HEAD: + case DRAGON_HEAD: + case ZOMBIE_HEAD: + case ZOMBIE_WALL_HEAD: + case CREEPER_WALL_HEAD: + case DRAGON_WALL_HEAD: + case WITHER_SKELETON_SKULL: + case LANTERN: + case SKELETON_WALL_SKULL: + case WITHER_SKELETON_WALL_SKULL: + case SNOW: { + miscNear = true; + break; + } + case BLACK_BED: + case BLUE_BED: + case BROWN_BED: + case CYAN_BED: + case GRAY_BED: + case GREEN_BED: + case LIME_BED: + case MAGENTA_BED: + case ORANGE_BED: + case PINK_BED: + case PURPLE_BED: + case RED_BED: + case WHITE_BED: + case YELLOW_BED: + case LIGHT_BLUE_BED: + case LIGHT_GRAY_BED: { + bedNear = true; + break; + } + } + } + } else if(blockBox.isCollided(normalBox)) { + XMaterial blockMaterial = getXMaterial(type); + if(blockMaterial != null) - switch(blockMaterial) { - case CAKE: - case BREWING_STAND: - case FLOWER_POT: - case PLAYER_HEAD: - case PLAYER_WALL_HEAD: - case SKELETON_SKULL: - case CREEPER_HEAD: - case DRAGON_HEAD: - case ZOMBIE_HEAD: - case ZOMBIE_WALL_HEAD: - case CREEPER_WALL_HEAD: - case DRAGON_WALL_HEAD: - case WITHER_SKELETON_SKULL: - case LANTERN: - case SKELETON_WALL_SKULL: - case WITHER_SKELETON_WALL_SKULL: - case SNOW: { - miscNear = true; - break; + switch(blockMaterial) { + case END_PORTAL: + case NETHER_PORTAL: { + inPortal = true; + break; + } } - case BLACK_BED: - case BLUE_BED: - case BROWN_BED: - case CYAN_BED: - case GRAY_BED: - case GREEN_BED: - case LIME_BED: - case MAGENTA_BED: - case ORANGE_BED: - case PINK_BED: - case PURPLE_BED: - case RED_BED: - case WHITE_BED: - case YELLOW_BED: - case LIGHT_BLUE_BED: - case LIGHT_GRAY_BED: { - bedNear = true; - break; - } - } } - } else if(blockBox.isCollided(normalBox)) { - XMaterial blockMaterial = getXMaterial(type); - - if(blockMaterial != null) - switch(blockMaterial) { - case END_PORTAL: - case NETHER_PORTAL: { - inPortal = true; - break; - } - } } } } diff --git a/src/main/java/dev/brighten/ac/data/handlers/GeneralInformation.java b/src/main/java/dev/brighten/ac/data/handlers/GeneralInformation.java index 08409ba..6cfda77 100644 --- a/src/main/java/dev/brighten/ac/data/handlers/GeneralInformation.java +++ b/src/main/java/dev/brighten/ac/data/handlers/GeneralInformation.java @@ -1,6 +1,7 @@ package dev.brighten.ac.data.handlers; import dev.brighten.ac.utils.PastLocation; +import dev.brighten.ac.utils.objects.evicting.EvictingList; import dev.brighten.ac.utils.timer.Timer; import dev.brighten.ac.utils.timer.impl.TickTimer; import lombok.Getter; @@ -8,6 +9,7 @@ import lombok.Setter; import org.bukkit.block.Block; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; +import org.bukkit.util.Vector; import java.util.Collections; import java.util.List; @@ -19,10 +21,11 @@ public class GeneralInformation { private Optional blockOnTo, blockBelow; private Timer lastMove = new TickTimer(), vehicleSwitch = new TickTimer(), lastSneak = new TickTimer(), velocity = new TickTimer(), - lastElytra = new TickTimer(); + lastElytra = new TickTimer(), blockAbove = new TickTimer(); private LivingEntity target; private boolean serverGround, lastServerGround, nearGround, worldLoaded, generalCancel, inVehicle, creative, - sneaking, sprinting, gliding, riptiding; + sneaking, sprinting, gliding, riptiding, wasOnSlime, onLadder, doingVelocity; private List nearbyEntities = Collections.emptyList(); private PastLocation targetPastLocation = new PastLocation(); + private List velocityHistory = Collections.synchronizedList(new EvictingList<>(5)); } diff --git a/src/main/java/dev/brighten/ac/data/handlers/MovementHandler.java b/src/main/java/dev/brighten/ac/data/handlers/MovementHandler.java index a28ad2b..67b8bf1 100644 --- a/src/main/java/dev/brighten/ac/data/handlers/MovementHandler.java +++ b/src/main/java/dev/brighten/ac/data/handlers/MovementHandler.java @@ -36,11 +36,11 @@ public class MovementHandler { @Getter private float lookX, lookY, lastLookX, lastLookY; @Getter - private float deltaYaw, deltaPitch, lDeltaYaw, lDeltaPitch, smoothYaw, smoothPitch, lsmoothYaw, lsmoothPitch, pitchGCD, lastPitchGCD, yawGCD, lastYawGCD; + private float deltaYaw, deltaPitch, lDeltaYaw, lDeltaPitch, pitchGCD, lastPitchGCD, yawGCD, lastYawGCD; private int moveTicks; private final List posLocs = new ArrayList<>(); @Getter - private boolean checkMovement, accurateYawData, cinematicMode; + private boolean checkMovement, accurateYawData, cinematic; @Getter @Setter private boolean excuseNextFlying; @@ -57,10 +57,11 @@ public class MovementHandler { private float sensitivityX, sensitivityY, currentSensX, currentSensY, sensitivityMcp, yawMode, pitchMode; @Getter private int sensXPercent, sensYPercent; + private int ticks; + private double lastX, lastY, lastLastY, lastYawAcelleration, lastPitchAcelleration; + private boolean inTick; @Getter private TickTimer lastCinematic = new TickTimer(2); - private MouseFilter mxaxis = new MouseFilter(), myaxis = new MouseFilter(); - private float smoothCamFilterX, smoothCamFilterY, smoothCamYaw, smoothCamPitch; private Timer lastReset = new TickTimer(2), generalProcess = new TickTimer(3); private final EvictingList sensitivitySamples = new EvictingList<>(50); @@ -71,12 +72,11 @@ public class MovementHandler { checkMovement = MovementUtils.checkMovement(player.getPlayerConnection()); - if(checkMovement) { + if (checkMovement) { moveTicks++; - } - else moveTicks = 0; + } else moveTicks = 0; - if(moveTicks > 0) { + if (moveTicks > 0) { updateLocations(packet); // Updating block locations @@ -84,19 +84,28 @@ public class MovementHandler { .getBlockAsync(to.getLoc().toLocation(player.getBukkitPlayer().getWorld()))); player.getInfo().setBlockBelow(BlockUtils .getBlockAsync(to.getLoc().toLocation(player.getBukkitPlayer().getWorld()) - .subtract(0,1,0))); + .subtract(0, 1, 0))); - if(packet.isMoved()) { + if (packet.isMoved()) { // Updating player bounding box player.getInfo().getLastMove().reset(); + + player.getInfo().setOnLadder(MovementUtils.isOnLadder(player)); } player.getBlockInformation().runCollisionCheck(); + + if(player.getBlockInformation().blocksAbove) { + player.getInfo().getBlockAbove().reset(); + } } + processVelocity(); + checkForTeleports(packet); if (packet.isLooked()) { + process(); float deltaYaw = Math.abs(this.deltaYaw), lastDeltaYaw = Math.abs(this.lDeltaYaw); final double differenceYaw = Math.abs(this.deltaYaw - lastDeltaYaw); final double differencePitch = Math.abs(this.deltaPitch - this.lDeltaPitch); @@ -117,9 +126,9 @@ public class MovementHandler { val origin = this.to.getLoc().clone(); - origin.y+= player.getInfo().isSneaking() ? 1.54 : 1.62; + origin.y += player.getInfo().isSneaking() ? 1.54 : 1.62; - if(lastTeleport.isPassed(1)) { + if (lastTeleport.isPassed(1)) { predictionHandling: { float yawGcd = this.yawGCD, @@ -132,7 +141,7 @@ public class MovementHandler { if (this.pitchGCD > 0.01 && this.pitchGCD < 1.2) pitchGcdList.add(pitchGcd); - if(yawGcdList.size() < 20 || pitchGcdList.size() < 20) { + if (yawGcdList.size() < 20 || pitchGcdList.size() < 20) { accurateYawData = false; break predictionHandling; } @@ -150,7 +159,8 @@ public class MovementHandler { sensXPercent = sensToPercent(sensitivityX = getSensitivityFromYawGCD(yawMode)); sensYPercent = sensToPercent(sensitivityY = getSensitivityFromPitchGCD(pitchMode)); - table: { + table: + { sensitivitySamples.add(Math.max(sensXPercent, sensYPercent)); if (sensitivitySamples.size() > 30) { @@ -167,50 +177,6 @@ public class MovementHandler { lookX = getExpiermentalDeltaX(player); lookY = getExpiermentalDeltaY(player); - if ((this.pitchGCD < 0.006 && this.yawGCD < 0.006) && smoothCamFilterY < 1E6 - && smoothCamFilterX < 1E6 && player.getCreation().isPassed(1000L)) { - float sens = MovementHandler.percentToSens(95); - float f = sens * 0.6f + .2f; - float f1 = f * f * f * 8; - float f2 = lookX * f1; - float f3 = lookY * f1; - - smoothCamFilterX = mxaxis.smooth(smoothCamYaw, .05f * f1); - smoothCamFilterY = myaxis.smooth(smoothCamPitch, .05f * f1); - - this.smoothCamYaw += f2; - this.smoothCamPitch += f3; - - f2 = smoothCamFilterX * 0.5f; - f3 = smoothCamFilterY * 0.5f; - - //val clampedFrom = (Math.abs(this.from.yaw) > 360 ? this.from.yaw % 360 : this.from.yaw); - val clampedFrom = MathUtils.yawTo180F(getFrom().getLoc().yaw); - float pyaw = clampedFrom + f2 * .15f; - float ppitch = this.getFrom().getLoc().pitch - f3 * .15f; - - this.lsmoothYaw = smoothYaw; - this.lsmoothPitch = smoothPitch; - this.smoothYaw = pyaw; - this.smoothPitch = ppitch; - - float yaccel = Math.abs(this.deltaYaw) - Math.abs(this.lDeltaYaw), - pAccel = Math.abs(this.deltaPitch) - Math.abs(this.lDeltaPitch); - - if (MathUtils.getDelta(smoothYaw, clampedFrom) > (yaccel > 0 ? (yaccel > 10 ? 2.5 : 1) : 0.3) - || MathUtils.getDelta(smoothPitch, this.getFrom().getLoc().pitch) - > (pAccel > 0 ? (pAccel > 10 ? 2.5 : 1) : 0.3)) { - smoothCamYaw = smoothCamPitch = 0; - this.cinematicMode = false; - mxaxis.reset(); - myaxis.reset(); - } else this.cinematicMode = true; - } else { - mxaxis.reset(); - myaxis.reset(); - this.cinematicMode = false; - } - lastLookX = lookX; lastLookY = lookY; lookX = getExpiermentalDeltaX(player); @@ -222,6 +188,10 @@ public class MovementHandler { } } + if (player.getInfo().isServerGround()) { + player.getInfo().setWasOnSlime(player.getBlockInformation().onSlime); + } + player.getInfo().setCreative(player.getBukkitPlayer().getGameMode() == GameMode.CREATIVE || player.getBukkitPlayer().getGameMode() == GameMode.SPECTATOR); @@ -232,8 +202,8 @@ public class MovementHandler { player.getInfo().setGliding(CompatHandler.getInstance().isGliding(player.getBukkitPlayer())); // Resetting glide/sneak timers - if(player.getInfo().isGliding()) player.getInfo().getLastElytra().reset(); - if(player.getInfo().isSneaking()) player.getInfo().getLastSneak().reset(); + if (player.getInfo().isGliding()) player.getInfo().getLastElytra().reset(); + if (player.getInfo().isSneaking()) player.getInfo().getLastSneak().reset(); player.getInfo().setGeneralCancel(player.getBukkitPlayer().getAllowFlight() || moveTicks == 0 @@ -250,8 +220,9 @@ public class MovementHandler { /* ata.playerInfo.generalCancel = data.getPlayer().getAllowFlight() - || this.creative - || hasLevi + || this.creativelastLastY + || hasLeviit +it || data.excuseNextFlying || data.getPlayer().isSleeping() || (this.lastGhostCollision.isNotPassed() && this.lastBlockPlace.isPassed(2)) @@ -270,6 +241,21 @@ public class MovementHandler { || Kauri.INSTANCE.lastTickLag.isNotPassed(5); */ } + // generate a method that processes velocityHistory and compares to current deltaY. + private void processVelocity() { + //Iterate through player.getInfo().getVelocityHistory() and compare to current deltaY. + val iterator = player.getInfo().getVelocityHistory().iterator(); + while (iterator.hasNext()) { + val velocity = iterator.next(); + + if(Math.abs(velocity.getY() - getDeltaY()) < 0.01) { + player.getInfo().getVelocity().reset(); + player.getOnVelocityTasks().forEach(vectorConsumer -> vectorConsumer.accept(velocity)); + iterator.remove(); + break; + } + } + } private static float getDeltaX(float yawDelta, float gcd) { return MathHelper.ceiling_float_int(yawDelta / gcd); @@ -278,6 +264,54 @@ public class MovementHandler { private static float getDeltaY(float pitchDelta, float gcd) { return MathHelper.ceiling_float_int(pitchDelta / gcd); } + public void process() { + + float yawAcelleration = Math.abs(getDeltaYaw()); + float pitchAcelleration = Math.abs(getDeltaPitch()); + + // They are not rotating + if (yawAcelleration < 0.002 || pitchAcelleration < 0.002) return; + + // Deltas between the current acelleration and last + double x = Math.abs(yawAcelleration - this.lastYawAcelleration); + double y = Math.abs(pitchAcelleration - this.lastPitchAcelleration); + + // Deltas between last X & Y + double deltaX = Math.abs(x - this.lastX); + double deltaY = Math.abs(y - this.lastY); + + // Pitch delta change + double pitchChangeAcelleration = Math.abs(this.lastLastY - deltaY); + this.inTick = false; + + // we have to check something different for pitch due to it being a little harder to check for being smooth + if (x < .04 || y < .04 + || (pitchAcelleration > .08 && pitchChangeAcelleration > 0 + && !MathUtils.isScientificNotation(pitchChangeAcelleration) + && pitchChangeAcelleration < .0855)) { + + if (this.isInvalidGCD()) { + this.ticks += (this.ticks < 20 ? 1 : 0); + } + } else { + this.ticks -= this.ticks > 0 ? 1 : 0; + } + + this.lastLastY = deltaY; + this.lastX = x; + this.lastY = y; + + this.lastYawAcelleration = yawAcelleration; + this.lastPitchAcelleration = pitchAcelleration; + + this.cinematic = this.ticks > 5; + + if(cinematic) lastCinematic.reset(); + } + + boolean isInvalidGCD() { + return pitchGCD < 0.0078125; + } public static float getExpiermentalDeltaX(APlayer data) { float deltaPitch = data.getMovement().getDeltaYaw(); @@ -291,11 +325,11 @@ public class MovementHandler { } public double[] getEyeHeights() { - if(player.getPlayerVersion().isOrAbove(ProtocolVersion.V1_14)) { - return new double[] {0.4f, 1.27f, 1.62f}; - } else if(player.getPlayerVersion().isOrAbove(ProtocolVersion.V1_9)) { - return new double[] {0.4f, 1.54f, 1.62f}; - } else return new double[] {1.54f, 1.62f}; + if (player.getPlayerVersion().isOrAbove(ProtocolVersion.V1_14)) { + return new double[]{0.4f, 1.27f, 1.62f}; + } else if (player.getPlayerVersion().isOrAbove(ProtocolVersion.V1_9)) { + return new double[]{0.4f, 1.54f, 1.62f}; + } else return new double[]{1.54f, 1.62f}; } public static float getExpiermentalDeltaY(APlayer data) { @@ -322,7 +356,7 @@ public class MovementHandler { } private static float getSensitivityFromPitchGCD(float gcd) { - return ((float)Math.cbrt(pitchToF3(gcd) / 8f) - .2f) / .6f; + return ((float) Math.cbrt(pitchToF3(gcd) / 8f) - .2f) / .6f; } private static float getF1FromYaw(float gcd) { @@ -344,7 +378,7 @@ public class MovementHandler { private static float getF1FromPitch(float gcd) { float f = getFFromPitch(gcd); - return (float)Math.pow(f, 3) * 8; + return (float) Math.pow(f, 3) * 8; } private static float yawToF2(float yawDelta) { @@ -360,20 +394,20 @@ public class MovementHandler { int i = 0; KLocation loc = new KLocation(packet.getX(), packet.getY(), packet.getZ(), packet.getYaw(), packet.getPitch()); - if(packet.getFlags().contains(WPacketPlayOutPosition.EnumPlayerTeleportFlags.X)) { - loc.x+= player.getMovement().getTo().getLoc().x; + if (packet.getFlags().contains(WPacketPlayOutPosition.EnumPlayerTeleportFlags.X)) { + loc.x += player.getMovement().getTo().getLoc().x; } - if(packet.getFlags().contains(WPacketPlayOutPosition.EnumPlayerTeleportFlags.Y)) { - loc.y+= player.getMovement().getTo().getLoc().y; + if (packet.getFlags().contains(WPacketPlayOutPosition.EnumPlayerTeleportFlags.Y)) { + loc.y += player.getMovement().getTo().getLoc().y; } - if(packet.getFlags().contains(WPacketPlayOutPosition.EnumPlayerTeleportFlags.Z)) { - loc.z+= player.getMovement().getTo().getLoc().z; + if (packet.getFlags().contains(WPacketPlayOutPosition.EnumPlayerTeleportFlags.Z)) { + loc.z += player.getMovement().getTo().getLoc().z; } - if(packet.getFlags().contains(WPacketPlayOutPosition.EnumPlayerTeleportFlags.X_ROT)) { - loc.pitch+= player.getMovement().getTo().getLoc().pitch; + if (packet.getFlags().contains(WPacketPlayOutPosition.EnumPlayerTeleportFlags.X_ROT)) { + loc.pitch += player.getMovement().getTo().getLoc().pitch; } - if(packet.getFlags().contains(WPacketPlayOutPosition.EnumPlayerTeleportFlags.Y_ROT)) { - loc.yaw+= player.getMovement().getTo().getLoc().yaw; + if (packet.getFlags().contains(WPacketPlayOutPosition.EnumPlayerTeleportFlags.Y_ROT)) { + loc.yaw += player.getMovement().getTo().getLoc().yaw; } teleportsToConfirm++; @@ -387,6 +421,7 @@ public class MovementHandler { /** * Updating the "to" and "from" location to current location. * Resetting position tracking; meant primarily for instant teleports. + * * @param location Location */ public void moveTo(Location location) { @@ -407,19 +442,19 @@ public class MovementHandler { } private void checkForTeleports(WPacketPlayInFlying packet) { - if(packet.isMoved() && packet.isLooked() && !packet.isOnGround()) { + if (packet.isMoved() && packet.isLooked() && !packet.isOnGround()) { synchronized (posLocs) { Iterator iterator = posLocs.iterator(); //Iterating through the ArrayList to find a potential teleport. We can't remove from the list //without causing a CME unless we use Iterator#remove(). - while(iterator.hasNext()) { + while (iterator.hasNext()) { KLocation posLoc = iterator.next(); KLocation to = new KLocation(packet.getX(), packet.getY(), packet.getZ()); double distance = MathUtils.getDistanceWithoutRoot(to, posLoc); - if(distance < 1E-9) { + if (distance < 1E-9) { lastTeleport.reset(); iterator.remove(); break; @@ -427,7 +462,7 @@ public class MovementHandler { } //Ensuring the list doesn't overflow with old locations, a potential crash exploit. - if(teleportsToConfirm == 0 && posLocs.size() > 0) { + if (teleportsToConfirm == 0 && posLocs.size() > 0) { posLocs.clear(); } } @@ -436,16 +471,17 @@ public class MovementHandler { /** * Setting the to and from to current location only if the player either moved or looked. + * * @param packet WPacketPlayInFlyingh */ private void setTo(WPacketPlayInFlying packet) { to.setWorld(player.getBukkitPlayer().getWorld()); - if(packet.isMoved()) { + if (packet.isMoved()) { to.getLoc().x = packet.getX(); to.getLoc().y = packet.getY(); to.getLoc().z = packet.getZ(); } - if(packet.isLooked()) { + if (packet.isLooked()) { to.getLoc().yaw = packet.getYaw(); to.getLoc().pitch = packet.getPitch(); } @@ -456,6 +492,7 @@ public class MovementHandler { /** * If from location is null, update to loc after to is set, otherwise, update to before from. * Updates the location of player and its general delta movement. + * * @param packet WPacketPlayInFlying */ private void updateLocations(WPacketPlayInFlying packet) { diff --git a/src/main/java/dev/brighten/ac/handler/PacketHandler.java b/src/main/java/dev/brighten/ac/handler/PacketHandler.java index e99e6d6..3dfe2c5 100644 --- a/src/main/java/dev/brighten/ac/handler/PacketHandler.java +++ b/src/main/java/dev/brighten/ac/handler/PacketHandler.java @@ -16,6 +16,7 @@ import net.minecraft.server.v1_8_R3.PacketPlayInSteerVehicle; import net.minecraft.server.v1_8_R3.PacketPlayInTransaction; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; +import org.bukkit.util.Vector; import java.util.*; @@ -127,7 +128,25 @@ public class PacketHandler { break; } case VELOCITY: { - player.runKeepaliveAction(ka -> player.getInfo().getVelocity().reset()); + WPacketPlayOutEntityVelocity packet = (WPacketPlayOutEntityVelocity) packetObject; + + if(packet.getEntityId() == player.getBukkitPlayer().getEntityId()) { + Vector velocity = new Vector(packet.getDeltaX(), packet.getDeltaY(), packet.getDeltaZ()); + player.getInfo().getVelocityHistory().add(velocity); + + player.runInstantAction(ka -> { + if(!ka.isEnd()) { + player.getInfo().setDoingVelocity(true); + } else if(player.getInfo().getVelocityHistory().contains(velocity)) { + player.getInfo().getVelocityHistory().remove(velocity); + player.getOnVelocityTasks().forEach(task -> task.accept(velocity)); + player.getInfo().setDoingVelocity(false); + player.getInfo().getVelocity().reset(); + } else { + player.getInfo().setDoingVelocity(false); + } + }); + } break; } case SERVER_POSITION: { 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 17c5b2d..e84dcb8 100644 --- a/src/main/java/dev/brighten/ac/packet/wrapper/PacketConverter.java +++ b/src/main/java/dev/brighten/ac/packet/wrapper/PacketConverter.java @@ -34,4 +34,6 @@ public interface PacketConverter { WPacketPlayOutBlockChange processBlockChange(Object object); WPacketPlayOutMultiBlockChange processMultiBlockChange(Object object); + + WPacketPlayOutEntityVelocity processVelocity(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 ffda609..87c3936 100644 --- a/src/main/java/dev/brighten/ac/packet/wrapper/PacketType.java +++ b/src/main/java/dev/brighten/ac/packet/wrapper/PacketType.java @@ -124,6 +124,8 @@ public enum PacketType { return convert.processBlockChange(object); case MULTI_BLOCK_CHANGE: return convert.processMultiBlockChange(object); + case VELOCITY: + return convert.processVelocity(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 151177f..b0334c1 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 @@ -291,4 +291,27 @@ public class Processor_18 implements PacketConverter { .changes(blockChanges) .build(); } + + @Override + public WPacketPlayOutEntityVelocity processVelocity(Object object) { + PacketPlayOutEntityVelocity packet = (PacketPlayOutEntityVelocity) object; + PacketDataSerializer serial = serialize(packet); + + return WPacketPlayOutEntityVelocity.builder() + .entityId(serial.e()) + .deltaX(serial.readShort() / 8000D) + .deltaY(serial.readShort() / 8000D) + .deltaZ(serial.readShort() / 8000D) + .build(); + } + + private PacketDataSerializer serialize(Packet packet) { + PacketDataSerializer serial = new PacketDataSerializer(Unpooled.buffer()); + try { + packet.b(serial); + } catch (IOException e) { + throw new RuntimeException(e); + } + return serial; + } } diff --git a/src/main/java/dev/brighten/ac/utils/MathUtils.java b/src/main/java/dev/brighten/ac/utils/MathUtils.java index ffc313e..50a6324 100644 --- a/src/main/java/dev/brighten/ac/utils/MathUtils.java +++ b/src/main/java/dev/brighten/ac/utils/MathUtils.java @@ -33,6 +33,10 @@ public class MathUtils { current - (float)Math.floor(current / previous) * previous); } + public static boolean isScientificNotation(double value) { + return String.valueOf(value).contains("E"); + } + public static double getDistanceWithoutRoot(KLocation one, KLocation two) { double deltaX = one.x - two.x, deltaY = one.y - two.y, deltaZ = one.z - two.z; diff --git a/src/main/java/dev/brighten/ac/utils/msg/ChatBuilder.java b/src/main/java/dev/brighten/ac/utils/msg/ChatBuilder.java index 4e9c15c..e6283d8 100644 --- a/src/main/java/dev/brighten/ac/utils/msg/ChatBuilder.java +++ b/src/main/java/dev/brighten/ac/utils/msg/ChatBuilder.java @@ -5,6 +5,7 @@ package dev.brighten.ac.utils.msg; +import dev.brighten.ac.utils.Color; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.chat.*; import net.md_5.bungee.api.chat.ComponentBuilder.FormatRetention; @@ -14,7 +15,7 @@ public class ChatBuilder { private ComponentBuilder componentBuilder; public ChatBuilder(String text, Object... objects) { - this.componentBuilder = new ComponentBuilder(String.format(text, objects)); + this.componentBuilder = new ComponentBuilder(String.format(Color.translate(text), objects)); } public ChatBuilder text(String text, Object... objects) { diff --git a/src/main/java/dev/brighten/ac/utils/world/BlockData.java b/src/main/java/dev/brighten/ac/utils/world/BlockData.java index 92b2260..321557c 100644 --- a/src/main/java/dev/brighten/ac/utils/world/BlockData.java +++ b/src/main/java/dev/brighten/ac/utils/world/BlockData.java @@ -1,12 +1,15 @@ package dev.brighten.ac.utils.world; import dev.brighten.ac.packet.ProtocolVersion; +import dev.brighten.ac.utils.BlockUtils; import dev.brighten.ac.utils.MiscUtils; import dev.brighten.ac.utils.ReflectionsUtil; import dev.brighten.ac.utils.XMaterial; +import dev.brighten.ac.utils.math.IntVector; import dev.brighten.ac.utils.world.blocks.*; import dev.brighten.ac.utils.world.types.*; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; @@ -437,6 +440,14 @@ public enum BlockData { return new DynamicCollisionBox(dynamic, block, version).offset(block.getX(), block.getY(), block.getZ()); } + public CollisionBox getBox(World world, IntVector block, ProtocolVersion version) { + if (this.box != null) + return this.box.copy().offset(block.getX(), block.getY(), block.getZ()); + return new DynamicCollisionBox(dynamic, + BlockUtils.getBlockAsync(block.toBukkitVector().toLocation(world)).orElse(null), version) + .offset(block.getX(), block.getY(), block.getZ()); + } + private static BlockData[] lookup = new BlockData[Material.values().length]; static {