diff --git a/src/main/java/dev/brighten/ac/check/impl/combat/Reach.java b/src/main/java/dev/brighten/ac/check/impl/combat/Reach.java index ab21149..8313b26 100644 --- a/src/main/java/dev/brighten/ac/check/impl/combat/Reach.java +++ b/src/main/java/dev/brighten/ac/check/impl/combat/Reach.java @@ -25,7 +25,7 @@ public class Reach extends Check { private int hbuffer; public Timer lastAimOnTarget = new TickTimer(); - private final Queue attacks = new LinkedBlockingQueue<>(); + private final Queue> attacks = new LinkedBlockingQueue<>(); private static final EnumSet allowedEntityTypes = EnumSet.of(EntityType.ZOMBIE, EntityType.SHEEP, EntityType.BLAZE, EntityType.SKELETON, EntityType.PLAYER, EntityType.VILLAGER, EntityType.IRON_GOLEM, @@ -39,7 +39,7 @@ public class Reach extends Check { public void onUse(WPacketPlayInUseEntity packet) { if(packet.getAction() == WPacketPlayInUseEntity.EnumEntityUseAction.ATTACK && allowedEntityTypes.contains(packet.getEntity(getPlayer().getBukkitPlayer().getWorld()).getType())) { - attacks.add(packet.getEntity(getPlayer().getBukkitPlayer().getWorld())); + attacks.add(new Tuple<>(packet.getEntity(getPlayer().getBukkitPlayer().getWorld()), getPlayer().getMovement().getTo().getLoc().clone())); } } @@ -49,11 +49,11 @@ public class Reach extends Check { attacks.clear(); return; } - Entity target; + Tuple target; while((target = attacks.poll()) != null) { //Updating new entity loc - Optional optionalEloc = getPlayer().getEntityLocationHandler().getEntityLocation(target); + Optional optionalEloc = getPlayer().getEntityLocationHandler().getEntityLocation(target.one); if(!optionalEloc.isPresent()) { return; @@ -61,16 +61,10 @@ public class Reach extends Check { final EntityLocation eloc = optionalEloc.get(); - final KLocation to = getPlayer().getMovement().getTo().getLoc().clone(), - from = getPlayer().getMovement().getFrom().getLoc().clone(); + final KLocation to = target.two; //debug("current loc: %.4f, %.4f, %.4f", eloc.x, eloc.y, eloc.z); - to.y+= getPlayer().getInfo().isSneaking() ? (ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_14) - ? 1.27f : 1.54f) : 1.62f; - from.y+= getPlayer().getInfo().isSneaking() ? (ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_14) - ? 1.27f : 1.54f) : 1.62f; - if(eloc.x == 0 && eloc.y == 0 & eloc.z == 0) { return; } @@ -82,29 +76,29 @@ public class Reach extends Check { if(eloc.oldLocations.size() > 0) { for (KLocation oldLocation : eloc.oldLocations) { SimpleCollisionBox box = (SimpleCollisionBox) - EntityData.getEntityBox(oldLocation.toVector(), target); + EntityData.getEntityBox(oldLocation.toVector(), target.one); if(getPlayer().getPlayerVersion().isBelow(ProtocolVersion.V1_9)) { - box = box.expand(0.1); + box = box.expand(0.1325); } else box = box.expand(0.0325); boxes.add(box); } for (KLocation oldLocation : eloc.interpolatedLocations) { SimpleCollisionBox box = (SimpleCollisionBox) - EntityData.getEntityBox(oldLocation.toVector(), target); + EntityData.getEntityBox(oldLocation.toVector(), target.one); if(getPlayer().getPlayerVersion().isBelow(ProtocolVersion.V1_9)) { - box = box.expand(0.1); + box = box.expand(0.1325); } else box = box.expand(0.0325); boxes.add(box); } } else { for (KLocation oldLocation : eloc.interpolatedLocations) { SimpleCollisionBox box = (SimpleCollisionBox) - EntityData.getEntityBox(oldLocation.toVector(), target); + EntityData.getEntityBox(oldLocation.toVector(), target.one); if(getPlayer().getPlayerVersion().isBelow(ProtocolVersion.V1_9)) { - box = box.expand(0.1); + box = box.expand(0.1325); } else box = box.expand(0.0325); boxes.add(box); } @@ -114,24 +108,41 @@ public class Reach extends Check { int hits = 0; - for (SimpleCollisionBox targetBox : boxes) { - final AxisAlignedBB vanillaBox = new AxisAlignedBB(targetBox); + boolean didSneakOrElytra = getPlayer().getInfo().getLastElytra().isNotPassed(40) + || getPlayer().getInfo().getLastElytra().isNotPassed(40); - Vec3D intersectTo = vanillaBox.rayTrace(to.toVector(), MathUtils.getDirection(to), 10), - intersectFrom = vanillaBox.rayTrace(from.toVector(), - MathUtils.getDirection(from), 10); + if(!didSneakOrElytra) { + to.y+= 1.62f; + for (SimpleCollisionBox targetBox : boxes) { + final AxisAlignedBB vanillaBox = new AxisAlignedBB(targetBox); - if(intersectTo != null) { - lastAimOnTarget.reset(); - hits++; - distance = Math.min(distance, intersectTo.distanceSquared(new Vec3D(to.x, to.y, to.z))); - collided = true; + Vec3D intersectTo = vanillaBox.rayTrace(to.toVector(), MathUtils.getDirection(to), 10); + + if(intersectTo != null) { + lastAimOnTarget.reset(); + hits++; + distance = Math.min(distance, intersectTo.distanceSquared(new Vec3D(to.x, to.y, to.z))); + collided = true; + } } - if(intersectFrom != null) { - lastAimOnTarget.reset(); - hits++; - distance = Math.min(distance, intersectFrom.distanceSquared(new Vec3D(from.x, from.y, from.z))); - collided = true; + //Checking all possible eyeheights since client actions notoriously desync from the server side + } else { + for (double eyeHeight : getPlayer().getMovement().getEyeHeights()) { + for (SimpleCollisionBox targetBox : boxes) { + final AxisAlignedBB vanillaBox = new AxisAlignedBB(targetBox); + + KLocation from = to.clone(); + + from.y+= eyeHeight; + Vec3D intersectTo = vanillaBox.rayTrace(from.toVector(), MathUtils.getDirection(from), 10); + + if(intersectTo != null) { + lastAimOnTarget.reset(); + hits++; + distance = Math.min(distance, intersectTo.distanceSquared(new Vec3D(from.x, from.y, from.z))); + collided = true; + } + } } } diff --git a/src/main/java/dev/brighten/ac/check/impl/speed/Speed.java b/src/main/java/dev/brighten/ac/check/impl/speed/Speed.java index d8e981f..9c65f24 100644 --- a/src/main/java/dev/brighten/ac/check/impl/speed/Speed.java +++ b/src/main/java/dev/brighten/ac/check/impl/speed/Speed.java @@ -9,10 +9,14 @@ import dev.brighten.ac.packet.ProtocolVersion; import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying; import dev.brighten.ac.utils.BlockUtils; import dev.brighten.ac.utils.MathHelper; +import dev.brighten.ac.utils.math.IntVector; +import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.craftbukkit.v1_8_R3.util.CraftMagicNumbers; import org.bukkit.potion.PotionEffectType; +import java.util.Deque; + @CheckData(name = "Speed", type = CheckType.MOVEMENT) public class Speed extends Check { private boolean lastLastClientGround; @@ -38,16 +42,17 @@ public class Speed extends Check { if (underBlock == null || lastUnderBlock == null) return; - float friction = CraftMagicNumbers.getBlock(underBlock).frictionFactor, - lfriction = CraftMagicNumbers.getBlock(lastUnderBlock).frictionFactor; + Deque frictionList = getPlayer().getBlockUpdateHandler() + .getPossibleMaterials(new IntVector(underBlock.getX(), underBlock.getY(), underBlock.getZ())), + lfrictionList = getPlayer().getBlockUpdateHandler() + .getPossibleMaterials(new IntVector(lastUnderBlock.getX(), lastUnderBlock.getY(), lastUnderBlock.getZ())); check: { if (!packet.isMoved() - /*|| getPlayer().playerInfo.generalCancel - || getPlayer().playerInfo.onLadder - || getPlayer().playerInfo.lastEntityCollision.isNotPassed(2) - || getPlayer().playerInfo.lastVelocity.isNotPassed(1)*/ + || getPlayer().getInfo().isGeneralCancel() + || getPlayer().getBlockInformation().onClimbable + || getPlayer().getInfo().getVelocity().isNotPassed(1) || getPlayer().getBlockInformation().inLiquid || getPlayer().getBlockInformation().collidesHorizontally) { break check; @@ -59,129 +64,137 @@ public class Speed extends Check { 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) { + for(Material underMaterial : frictionList) { + for(Material lastUnderMaterial : lfrictionList) { + 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) { - float forward = f, strafe = s; + float forward = f, strafe = s; - if (sneaking) { - forward *= 0.3; - strafe *= 0.3; - } + if (sneaking) { + forward *= 0.3; + strafe *= 0.3; + } - if (using) { - forward *= 0.2; - strafe *= 0.2; - } + float friction = CraftMagicNumbers.getBlock(underMaterial).frictionFactor; + float lfriction = CraftMagicNumbers.getBlock(lastUnderMaterial).frictionFactor; - //Multiplying by 0.98 like in client - forward *= 0.9800000190734863F; - strafe *= 0.9800000190734863F; + if (using) { + forward *= 0.2; + strafe *= 0.2; + } - double aiMoveSpeed = getPlayer().getBukkitPlayer().getWalkSpeed() / 2; + //Multiplying by 0.98 like in client + forward *= 0.9800000190734863F; + strafe *= 0.9800000190734863F; - float drag = 0.91f; - double lmotionX = getPlayer().getMovement().getLDeltaX(), - lmotionZ = getPlayer().getMovement().getLDeltaZ(); + double aiMoveSpeed = getPlayer().getBukkitPlayer().getWalkSpeed() / 2; - //The "1" will effectively remove lastFriction from the equation - lmotionX *= (lastLastClientGround ? lfriction : 1) * 0.9100000262260437D; - lmotionZ *= (lastLastClientGround ? lfriction : 1) * 0.9100000262260437D; + float drag = 0.91f; + double lmotionX = getPlayer().getMovement().getLDeltaX(), + lmotionZ = getPlayer().getMovement().getLDeltaZ(); - //Running multiplication done after previous prediction - if (getPlayer().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; - } + //The "1" will effectively remove lastFriction from the equation + lmotionX *= (lastLastClientGround ? lfriction : 1) * 0.9100000262260437D; + lmotionZ *= (lastLastClientGround ? lfriction : 1) * 0.9100000262260437D; - // Attack slowdown - if (attack) { - lmotionX *= 0.6; - lmotionZ *= 0.6; - } + //Running multiplication done after previous prediction + if (getPlayer().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 (sprinting) aiMoveSpeed += aiMoveSpeed * 0.30000001192092896D; + // Attack slowdown + if (attack) { + lmotionX *= 0.6; + lmotionZ *= 0.6; + } - if (getPlayer().getPotionHandler().hasPotionEffect(PotionEffectType.SPEED)) - aiMoveSpeed += (getPlayer().getPotionHandler().getEffectByType(PotionEffectType.SPEED) - .get() - .getAmplifier() + 1) * (double) 0.20000000298023224D * aiMoveSpeed; - if (getPlayer().getPotionHandler().hasPotionEffect(PotionEffectType.SLOW)) - aiMoveSpeed += (getPlayer().getPotionHandler().getEffectByType(PotionEffectType.SLOW) - .get() - .getAmplifier() + 1) * (double) -0.15000000596046448D * aiMoveSpeed; + if (sprinting) + aiMoveSpeed += aiMoveSpeed * 0.30000001192092896D; - float f5; - if (onGround) { - drag *= friction; + if (getPlayer().getPotionHandler().hasPotionEffect(PotionEffectType.SPEED)) + aiMoveSpeed += (getPlayer().getPotionHandler().getEffectByType(PotionEffectType.SPEED) + .get() + .getAmplifier() + 1) * (double) 0.20000000298023224D * aiMoveSpeed; + if (getPlayer().getPotionHandler().hasPotionEffect(PotionEffectType.SLOW)) + aiMoveSpeed += (getPlayer().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; - if (sprinting && jumped) { - float rot = getPlayer().getMovement().getTo().getLoc().yaw * 0.017453292F; - lmotionX -= sin(fastMath, rot) * 0.2F; - lmotionZ += cos(fastMath, rot) * 0.2F; - } + f5 = (float) (aiMoveSpeed * (0.16277136F / (drag * drag * drag))); - } else f5 = sprinting ? 0.025999999F : 0.02f; + if (sprinting && jumped) { + float rot = getPlayer().getMovement().getTo().getLoc().yaw * 0.017453292F; + lmotionX -= sin(fastMath, rot) * 0.2F; + lmotionZ += cos(fastMath, rot) * 0.2F; + } - if (getPlayer().getPlayerVersion().isOrAbove(ProtocolVersion.V1_9)) { - double keyedMotion = forward * forward + strafe * strafe; + } else f5 = sprinting ? 0.025999999F : 0.02f; - if (keyedMotion >= 1.0E-4F) { - keyedMotion = f5 / Math.max(1.0, Math.sqrt(keyedMotion)); - forward *= keyedMotion; - strafe *= keyedMotion; + if (getPlayer().getPlayerVersion().isOrAbove(ProtocolVersion.V1_9)) { + double keyedMotion = forward * forward + strafe * strafe; - final float yawSin = sin(fastMath, - getPlayer().getMovement().getTo().getLoc().yaw * (float) Math.PI / 180.F), - yawCos = cos(fastMath, - getPlayer().getMovement().getTo().getLoc().yaw * (float) Math.PI / 180.F); + if (keyedMotion >= 1.0E-4F) { + keyedMotion = f5 / Math.max(1.0, Math.sqrt(keyedMotion)); + forward *= keyedMotion; + strafe *= keyedMotion; - lmotionX += (strafe * yawCos - forward * yawSin); - lmotionZ += (forward * yawCos + strafe * yawSin); - } - } else { - float keyedMotion = forward * forward + strafe * strafe; + final float yawSin = sin(fastMath, + getPlayer().getMovement().getTo().getLoc().yaw * (float) Math.PI / 180.F), + yawCos = cos(fastMath, + getPlayer().getMovement().getTo().getLoc().yaw * (float) Math.PI / 180.F); - if (keyedMotion >= 1.0E-4F) { - keyedMotion = f5 / Math.max(1.0f, MathHelper.sqrt_float(keyedMotion)); - forward *= keyedMotion; - strafe *= keyedMotion; + lmotionX += (strafe * yawCos - forward * yawSin); + lmotionZ += (forward * yawCos + strafe * yawSin); + } + } else { + float keyedMotion = forward * forward + strafe * strafe; - final float yawSin = sin(fastMath, - getPlayer().getMovement().getTo().getLoc().yaw * (float) Math.PI / 180.F), - yawCos = cos(fastMath, - getPlayer().getMovement().getTo().getLoc().yaw * (float) Math.PI / 180.F); + if (keyedMotion >= 1.0E-4F) { + keyedMotion = f5 / Math.max(1.0f, MathHelper.sqrt_float(keyedMotion)); + forward *= keyedMotion; + strafe *= keyedMotion; - lmotionX += (strafe * yawCos - forward * yawSin); - lmotionZ += (forward * yawCos + strafe * yawSin); - } - } + final float yawSin = sin(fastMath, + getPlayer().getMovement().getTo().getLoc().yaw * (float) Math.PI / 180.F), + yawCos = cos(fastMath, + getPlayer().getMovement().getTo().getLoc().yaw * (float) Math.PI / 180.F); - double diffX = getPlayer().getMovement().getDeltaX() - lmotionX, - diffZ = getPlayer().getMovement().getDeltaZ() - lmotionZ; - double delta = (diffX * diffX) + (diffZ * diffZ); + lmotionX += (strafe * yawCos - forward * yawSin); + lmotionZ += (forward * yawCos + strafe * yawSin); + } + } - if (delta < smallestDelta) { - smallestDelta = delta; - pmotionx = lmotionX; - pmotionz = lmotionZ; + double diffX = getPlayer().getMovement().getDeltaX() - lmotionX, + diffZ = getPlayer().getMovement().getDeltaZ() - lmotionZ; + double delta = (diffX * diffX) + (diffZ * diffZ); - if (delta < 1E-15) { - break loop; + if (delta < smallestDelta) { + smallestDelta = delta; + pmotionx = lmotionX; + pmotionz = lmotionZ; + + if (delta < 1E-15) { + break loop; + } + } } } } diff --git a/src/main/java/dev/brighten/ac/command/AnticheatCommand.java b/src/main/java/dev/brighten/ac/command/AnticheatCommand.java index 9bd5a8a..606fe1f 100644 --- a/src/main/java/dev/brighten/ac/command/AnticheatCommand.java +++ b/src/main/java/dev/brighten/ac/command/AnticheatCommand.java @@ -7,10 +7,14 @@ import dev.brighten.ac.check.Check; 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 io.netty.buffer.Unpooled; +import net.minecraft.server.v1_8_R3.PacketDataSerializer; +import net.minecraft.server.v1_8_R3.PacketPlayOutCustomPayload; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -96,4 +100,23 @@ public class AnticheatCommand extends BaseCommand { sender.sendMessage(MiscUtils.line(Color.Dark_Gray)); }); } + + @Subcommand("runtest") + public void onCommand(Player player) { + long start = System.currentTimeMillis(); + PacketDataSerializer serializer = new PacketDataSerializer(Unpooled.buffer()); + serializer.writeLong(start); + PacketPlayOutCustomPayload payload = new PacketPlayOutCustomPayload("Time|Send", serializer); + + HandlerAbstract.getHandler().sendPacket(player, payload); + Anticheat.INSTANCE.getPlayerRegistry().getPlayer(player.getUniqueId()).ifPresent(aplayer -> { + aplayer.runInstantAction(ka -> { + if(!ka.isEnd()) { + long transDelta = System.currentTimeMillis() - start; + + player.sendMessage("Transaction delta: " + transDelta + "ms"); + } + }); + }); + } } diff --git a/src/main/java/dev/brighten/ac/data/APlayer.java b/src/main/java/dev/brighten/ac/data/APlayer.java index d8ee844..42b2d11 100644 --- a/src/main/java/dev/brighten/ac/data/APlayer.java +++ b/src/main/java/dev/brighten/ac/data/APlayer.java @@ -11,6 +11,7 @@ import dev.brighten.ac.data.obj.InstantAction; import dev.brighten.ac.data.obj.NormalAction; import dev.brighten.ac.handler.EntityLocationHandler; import dev.brighten.ac.handler.PotionHandler; +import dev.brighten.ac.handler.block.BlockUpdateHandler; import dev.brighten.ac.handler.keepalive.KeepAlive; import dev.brighten.ac.handler.protocolsupport.ProtocolAPI; import dev.brighten.ac.messages.Messages; @@ -45,6 +46,10 @@ public class APlayer { private PotionHandler potionHandler; @Getter private EntityLocationHandler entityLocationHandler; + + @Getter + private BlockUpdateHandler blockUpdateHandler; + @Getter private GeneralInformation info; @Getter @@ -87,6 +92,7 @@ public class APlayer { this.movement = new MovementHandler(this); this.potionHandler = new PotionHandler(this); this.entityLocationHandler = new EntityLocationHandler(this); + this.blockUpdateHandler = new BlockUpdateHandler(this); this.info = new GeneralInformation(); this.lagInfo = new LagInformation(); this.blockInformation = new BlockInformation(this); 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 4daf7e2..08409ba 100644 --- a/src/main/java/dev/brighten/ac/data/handlers/GeneralInformation.java +++ b/src/main/java/dev/brighten/ac/data/handlers/GeneralInformation.java @@ -17,10 +17,12 @@ import java.util.Optional; @Setter public class GeneralInformation { private Optional blockOnTo, blockBelow; - private Timer lastMove = new TickTimer(), vehicleSwitch = new TickTimer(); + private Timer lastMove = new TickTimer(), vehicleSwitch = new TickTimer(), + lastSneak = new TickTimer(), velocity = new TickTimer(), + lastElytra = new TickTimer(); private LivingEntity target; private boolean serverGround, lastServerGround, nearGround, worldLoaded, generalCancel, inVehicle, creative, - sneaking, sprinting; + sneaking, sprinting, gliding, riptiding; private List nearbyEntities = Collections.emptyList(); - private PastLocation targetPastLocation = new PastLocation();; + private PastLocation targetPastLocation = new PastLocation(); } 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 7a219b9..a28ad2b 100644 --- a/src/main/java/dev/brighten/ac/data/handlers/MovementHandler.java +++ b/src/main/java/dev/brighten/ac/data/handlers/MovementHandler.java @@ -228,6 +228,13 @@ public class MovementHandler { boolean hasLevitation = ProtocolVersion.getGameVersion().isOrAbove(ProtocolVersion.V1_9) && player.getPotionHandler().hasPotionEffect(XPotion.LEVITATION.getPotionEffectType()); + player.getInfo().setRiptiding(CompatHandler.getInstance().isRiptiding(player.getBukkitPlayer())); + 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(); + player.getInfo().setGeneralCancel(player.getBukkitPlayer().getAllowFlight() || moveTicks == 0 || excuseNextFlying @@ -237,8 +244,8 @@ public class MovementHandler { || player.getInfo().isInVehicle() || player.getInfo().getVehicleSwitch().isNotPassed(1) || player.getBukkitPlayer().isSleeping() - || CompatHandler.getInstance().isRiptiding(player.getBukkitPlayer()) - || CompatHandler.getInstance().isGliding(player.getBukkitPlayer()) + || player.getInfo().isGliding() + || player.getInfo().isRiptiding() || hasLevitation); /* @@ -283,6 +290,14 @@ public class MovementHandler { return result; } + 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}; + } + public static float getExpiermentalDeltaY(APlayer data) { float deltaPitch = data.getMovement().getDeltaPitch(); float sens = data.getMovement().sensitivityY; diff --git a/src/main/java/dev/brighten/ac/handler/EntityLocationHandler.java b/src/main/java/dev/brighten/ac/handler/EntityLocationHandler.java index 5172234..be8fc64 100644 --- a/src/main/java/dev/brighten/ac/handler/EntityLocationHandler.java +++ b/src/main/java/dev/brighten/ac/handler/EntityLocationHandler.java @@ -85,8 +85,6 @@ public class EntityLocationHandler { eloc.newPitch += packet.getPitch(); eloc.increment = 3; - - eloc.interpolatedLocations.clear(); }); } @@ -120,7 +118,6 @@ public class EntityLocationHandler { eloc.newZ = eloc.z = packet.getZ(); eloc.newYaw = eloc.yaw = packet.getYaw(); eloc.newPitch = eloc.pitch = packet.getPitch(); - eloc.interpolatedLocations.clear(); } else { eloc.newX = packet.getX(); eloc.newY = packet.getY(); @@ -129,7 +126,6 @@ public class EntityLocationHandler { eloc.newPitch = packet.getPitch(); eloc.increment = 3; - eloc.interpolatedLocations.clear(); } } else { //We don't need to do version checking here. Atlas handles this for us. @@ -159,6 +155,7 @@ public class EntityLocationHandler { if(data.getInfo().getTarget() != null && data.getInfo().getTarget().getEntityId() == entity.getEntityId()) { data.runInstantAction(ia -> { if(!ia.isEnd()) { + action.run(); } else entityLocationMap.get(entity.getUniqueId()).oldLocations.clear(); }); diff --git a/src/main/java/dev/brighten/ac/handler/PacketHandler.java b/src/main/java/dev/brighten/ac/handler/PacketHandler.java index 3a65511..d8a7820 100644 --- a/src/main/java/dev/brighten/ac/handler/PacketHandler.java +++ b/src/main/java/dev/brighten/ac/handler/PacketHandler.java @@ -5,13 +5,13 @@ import dev.brighten.ac.data.APlayer; import dev.brighten.ac.data.obj.NormalAction; import dev.brighten.ac.packet.ProtocolVersion; import dev.brighten.ac.packet.wrapper.PacketType; -import dev.brighten.ac.packet.wrapper.in.WPacketPlayInEntityAction; -import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying; -import dev.brighten.ac.packet.wrapper.in.WPacketPlayInUseEntity; +import dev.brighten.ac.packet.wrapper.in.*; import dev.brighten.ac.packet.wrapper.out.*; import dev.brighten.ac.utils.KLocation; import dev.brighten.ac.utils.MovementUtils; import lombok.val; +import net.minecraft.server.v1_8_R3.PacketDataSerializer; +import net.minecraft.server.v1_8_R3.PacketPlayInCustomPayload; import net.minecraft.server.v1_8_R3.PacketPlayInSteerVehicle; import net.minecraft.server.v1_8_R3.PacketPlayInTransaction; import org.bukkit.entity.Entity; @@ -108,12 +108,28 @@ public class PacketHandler { player.getMovement().process(packet, System.currentTimeMillis()); break; } + case BLOCK_CHANGE: { + WPacketPlayOutBlockChange packet = (WPacketPlayOutBlockChange) packetObject; + + player.getBlockUpdateHandler().runUpdate(packet); + break; + } + case MULTI_BLOCK_CHANGE: { + WPacketPlayOutMultiBlockChange packet = (WPacketPlayOutMultiBlockChange) packetObject; + + player.getBlockUpdateHandler().runUpdate(packet); + break; + } case ENTITY_EFFECT: { WPacketPlayOutEntityEffect packet = (WPacketPlayOutEntityEffect) packetObject; player.getPotionHandler().onPotionEffect(packet); break; } + case VELOCITY: { + player.runKeepaliveAction(ka -> player.getInfo().getVelocity().reset()); + break; + } case SERVER_POSITION: { player.getMovement().addPosition((WPacketPlayOutPosition) packetObject); break; @@ -141,6 +157,24 @@ public class PacketHandler { break; } + case CLIENT_PAYLOAD: { + PacketPlayInCustomPayload packet = (PacketPlayInCustomPayload) packetObject; + + if(packet.a().equals("Time|Receive")) { + PacketDataSerializer serial = packet.b(); + + long serverTime = serial.readLong(); + long clientReceivedTime = serial.readLong(); + long currentTime = System.currentTimeMillis(); + + long serverPing = clientReceivedTime - serverTime; + long clientToServer = currentTime - clientReceivedTime; + long totalFeedback = currentTime - serverTime; + + player.getBukkitPlayer().sendMessage(String.format("total: %sms client-server: %sms server-client: %sms", totalFeedback, clientToServer, serverPing)); + } + break; + } case ENTITY_ACTION: { WPacketPlayInEntityAction packet = (WPacketPlayInEntityAction) packetObject; @@ -189,6 +223,18 @@ public class PacketHandler { } break; } + case BLOCK_DIG: { + WPacketPlayInBlockPlace packet = (WPacketPlayInBlockPlace) packetObject; + + player.getBlockUpdateHandler().onPlace(packet); + break; + } + case BLOCK_PLACE: { + WPacketPlayInBlockDig packet = (WPacketPlayInBlockDig) packetObject; + + player.getBlockUpdateHandler().onDig(packet); + break; + } } player.callPacket(packetObject); diff --git a/src/main/java/dev/brighten/ac/handler/block/BlockUpdateHandler.java b/src/main/java/dev/brighten/ac/handler/block/BlockUpdateHandler.java new file mode 100644 index 0000000..2c6fb10 --- /dev/null +++ b/src/main/java/dev/brighten/ac/handler/block/BlockUpdateHandler.java @@ -0,0 +1,137 @@ +package dev.brighten.ac.handler.block; + +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.WPacketPlayOutMultiBlockChange; +import dev.brighten.ac.utils.BlockUtils; +import dev.brighten.ac.utils.Tuple; +import dev.brighten.ac.utils.math.IntVector; +import lombok.RequiredArgsConstructor; +import lombok.val; +import org.bukkit.Material; +import org.bukkit.block.Block; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +@RequiredArgsConstructor +public class BlockUpdateHandler { + private final Map> blockInformation = new ConcurrentHashMap<>(); + + private final APlayer player; + + public void onWorldChange() { + blockInformation.clear(); + } + + /** + * Keep track of block placements since the Bukkit API will be a bit behind + * @param place + */ + public void onPlace(WPacketPlayInBlockPlace place) { + if(!place.getItemStack().getType().isBlock()) return; + + Deque possible = getPossibleMaterials(place.getBlockPos()); + possible.add(place.getItemStack().getType()); + } + + /** + * Keep track of block breaking since the Bukkit API will be a bit behind. + * @param dig + */ + public void onDig(WPacketPlayInBlockDig dig) { + Deque possible = getPossibleMaterials(dig.getBlockPos()); + possible.clear(); + possible.add(Material.AIR); + } + + public void runUpdate(WPacketPlayOutBlockChange packet) { + Deque blockInfo = blockInformation.compute(packet.getBlockLocation(), (blockLoc, blockI) -> { + if(blockI == null) { + blockI = new LinkedList<>(); + + val optional = BlockUtils + .getBlockAsync(packet.getBlockLocation().toBukkitVector() + .toLocation(player.getBukkitPlayer().getWorld())); + + if(optional.isPresent()) { + Block block = optional.get(); + + blockI.add(block.getType()); + } + } + + return blockI; + }); + + // Updating block information + player.runInstantAction(k -> { + if(!k.isEnd()) { + blockInfo.add(packet.getMaterial()); + } else if(blockInfo.size() > 1) { + blockInfo.removeFirst(); + } + }); + } + + public void runUpdate(WPacketPlayOutMultiBlockChange packet) { + List, Material>> changes = new ArrayList<>(); + for (WPacketPlayOutMultiBlockChange.BlockChange change : packet.getChanges()) { + Deque blockInfo = blockInformation.compute(change.getLocation(), (blockLoc, blockI) -> { + if(blockI == null) { + blockI = new LinkedList<>(); + + val optional = BlockUtils + .getBlockAsync(change.getLocation().toBukkitVector() + .toLocation(player.getBukkitPlayer().getWorld())); + + if(optional.isPresent()) { + Block block = optional.get(); + + blockI.add(block.getType()); + } + } + + return blockI; + }); + + changes.add(new Tuple<>(blockInfo, change.getMaterial())); + } + + player.runInstantAction(k -> { + if(!k.isEnd()) { + for (Tuple, Material> tuple : changes) { + tuple.one.add(tuple.two); + } + } else { + for (Tuple, Material> tuple : changes) { + if(tuple.one.size() > 1) { + tuple.one.removeFirst(); + } + } + } + }); + } + + public Deque getPossibleMaterials(IntVector loc) { + return blockInformation.compute(loc, (blockLoc, blockI) -> { + if(blockI == null) { + blockI = new LinkedList<>(); + + val optional = BlockUtils + .getBlockAsync(loc.toBukkitVector() + .toLocation(player.getBukkitPlayer().getWorld())); + + if(optional.isPresent()) { + Block block = optional.get(); + + blockI.add(block.getType()); + } + } + + return blockI; + }); + } +} diff --git a/src/main/java/dev/brighten/ac/listener/JoinListener.java b/src/main/java/dev/brighten/ac/listener/JoinListener.java index 52350ba..f113ed2 100644 --- a/src/main/java/dev/brighten/ac/listener/JoinListener.java +++ b/src/main/java/dev/brighten/ac/listener/JoinListener.java @@ -13,6 +13,7 @@ import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerKickEvent; import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerTeleportEvent; import java.util.Optional; @@ -82,6 +83,14 @@ public class JoinListener implements Listener { player.callEvent(event); } + @EventHandler + public void onTeleport(PlayerTeleportEvent event) { + if(event.getFrom().getWorld().equals(event.getTo().getWorld())) return; + + Anticheat.INSTANCE.getPlayerRegistry().getPlayer(event.getPlayer().getUniqueId()) + .ifPresent(player -> player.getBlockUpdateHandler().onWorldChange()); + } + @EventHandler public void onQuit(PlayerQuitEvent event) { Anticheat.INSTANCE.getPlayerRegistry().unregister(event.getPlayer().getUniqueId()); 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 cdc5479..17c5b2d 100644 --- a/src/main/java/dev/brighten/ac/packet/wrapper/PacketConverter.java +++ b/src/main/java/dev/brighten/ac/packet/wrapper/PacketConverter.java @@ -30,4 +30,8 @@ public interface PacketConverter { WPacketPlayOutEntityTeleport processEntityTeleport(Object object); WPacketHandshakingInSetProtocol processHandshakingProtocol(Object object); + + WPacketPlayOutBlockChange processBlockChange(Object object); + + WPacketPlayOutMultiBlockChange processMultiBlockChange(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 af40dce..ffda609 100644 --- a/src/main/java/dev/brighten/ac/packet/wrapper/PacketType.java +++ b/src/main/java/dev/brighten/ac/packet/wrapper/PacketType.java @@ -85,13 +85,6 @@ public enum PacketType { return Optional.empty(); } - public static class Login { - public static final String HANDSHAKE = "PacketHandshakingInSetProtocol"; - public static final String PING = "PacketStatusInPing"; - public static final String STATUS_START = "PacketStatusInStart"; - public static final String LOGIN_START = "PacketLoginInStart"; - } - public static Object processType(PacketType type, Object object) { PacketConverter convert = Anticheat.INSTANCE.getPacketProcessor().getPacketConverter(); @@ -127,6 +120,10 @@ public enum PacketType { return convert.processEntityTeleport(object); case LOGIN_HANDSHAKE: return convert.processHandshakingProtocol(object); + case BLOCK_CHANGE: + return convert.processBlockChange(object); + case MULTI_BLOCK_CHANGE: + return convert.processMultiBlockChange(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 4d399d2..151177f 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 @@ -9,7 +9,9 @@ import dev.brighten.ac.utils.reflections.types.WrappedClass; import dev.brighten.ac.utils.reflections.types.WrappedField; import io.netty.buffer.Unpooled; import net.minecraft.server.v1_8_R3.*; +import org.bukkit.Material; import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_8_R3.util.CraftMagicNumbers; import org.bukkit.util.Vector; import java.io.IOException; @@ -238,4 +240,55 @@ public class Processor_18 implements PacketConverter { .protocol(WPacketHandshakingInSetProtocol.EnumProtocol.valueOf(EnumProtocol.a(serial.e()).name())) .build(); } + + @Override + public WPacketPlayOutBlockChange processBlockChange(Object object) { + PacketPlayOutBlockChange packet = (PacketPlayOutBlockChange) object; + PacketDataSerializer serial = new PacketDataSerializer(Unpooled.buffer()); + + try { + packet.b(serial); + } catch (IOException e) { + throw new RuntimeException(e); + } + + BlockPosition blockPos = serial.c(); + IntVector vecPos = new IntVector(blockPos.getX(), blockPos.getY(), blockPos.getZ()); + Material material = CraftMagicNumbers.getMaterial(packet.block.getBlock()); + + return WPacketPlayOutBlockChange.builder() + .blockLocation(vecPos) + .material(material) + .build(); + } + + @Override + public WPacketPlayOutMultiBlockChange processMultiBlockChange(Object object) { + PacketPlayOutMultiBlockChange packet = (PacketPlayOutMultiBlockChange) object; + PacketDataSerializer serial = new PacketDataSerializer(Unpooled.buffer()); + + try { + packet.b(serial); + } catch (IOException e) { + throw new RuntimeException(e); + } + + final int[] chunkLoc = new int[] {serial.readInt(), serial.readInt()}; + final WPacketPlayOutMultiBlockChange.BlockChange[] + blockChanges = new WPacketPlayOutMultiBlockChange.BlockChange[serial.e()]; + + for (int i = 0; i < blockChanges.length; i++) { + short encodedloc = serial.readShort(); + + IntVector loc = new IntVector(encodedloc >> 12 & 15, encodedloc & 255, encodedloc >> 8 & 15); + Material blockType = CraftMagicNumbers.getMaterial(Block.d.a(serial.e()).getBlock()); + + blockChanges[i] = new WPacketPlayOutMultiBlockChange.BlockChange(loc, blockType); + } + + return WPacketPlayOutMultiBlockChange.builder() + .chunk(chunkLoc) + .changes(blockChanges) + .build(); + } } diff --git a/src/main/java/dev/brighten/ac/utils/Vec3D.java b/src/main/java/dev/brighten/ac/utils/Vec3D.java index 20af9c3..e6d0319 100644 --- a/src/main/java/dev/brighten/ac/utils/Vec3D.java +++ b/src/main/java/dev/brighten/ac/utils/Vec3D.java @@ -8,6 +8,7 @@ package dev.brighten.ac.utils; import org.bukkit.Location; import javax.annotation.Nullable; +import java.util.Objects; public class Vec3D { public static final Vec3D a = new Vec3D(0.0D, 0.0D, 0.0D); @@ -138,33 +139,6 @@ public class Vec3D { } } - public boolean equals(Object var1) { - if (this == var1) { - return true; - } else if (!(var1 instanceof Vec3D)) { - return false; - } else { - Vec3D var2 = (Vec3D)var1; - if (Double.compare(var2.x, this.x) != 0) { - return false; - } else if (Double.compare(var2.y, this.y) != 0) { - return false; - } else { - return Double.compare(var2.z, this.z) == 0; - } - } - } - - public int hashCode() { - long var2 = Double.doubleToLongBits(this.x); - int var1 = (int)(var2 ^ var2 >>> 32); - var2 = Double.doubleToLongBits(this.y); - var1 = 31 * var1 + (int)(var2 ^ var2 >>> 32); - var2 = Double.doubleToLongBits(this.z); - var1 = 31 * var1 + (int)(var2 ^ var2 >>> 32); - return var1; - } - public String toString() { return "(" + this.x + ", " + this.y + ", " + this.z + ")"; } @@ -186,4 +160,17 @@ public class Vec3D { double var8 = this.z * (double)var2 - this.x * (double)var3; return new Vec3D(var4, var6, var8); } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Vec3D vec3D = (Vec3D) o; + return Double.compare(vec3D.x, x) == 0 && Double.compare(vec3D.y, y) == 0 && Double.compare(vec3D.z, z) == 0; + } + + @Override + public int hashCode() { + return Objects.hash(x, y, z); + } } diff --git a/src/main/java/dev/brighten/ac/utils/math/IntVector.java b/src/main/java/dev/brighten/ac/utils/math/IntVector.java index 205d6fb..8d35104 100644 --- a/src/main/java/dev/brighten/ac/utils/math/IntVector.java +++ b/src/main/java/dev/brighten/ac/utils/math/IntVector.java @@ -6,6 +6,8 @@ import lombok.NoArgsConstructor; import lombok.Setter; import org.bukkit.util.Vector; +import java.util.Objects; + @AllArgsConstructor @NoArgsConstructor public class IntVector { @@ -25,4 +27,17 @@ public class IntVector { public String toString() { return String.format("IntVector[%s, %s, %s]", x, y, z); } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + IntVector intVector = (IntVector) o; + return x == intVector.x && y == intVector.y && z == intVector.z; + } + + @Override + public int hashCode() { + return Objects.hash(x, y, z); + } }