diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..dfe0770
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+# Auto detect text files and perform LF normalization
+* text=auto
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..dcf923a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,36 @@
+# Eclipse stuff
+.classpath
+.project
+.settings/
+
+# netbeans
+nbproject/
+nbactions.xml
+
+# we use maven!
+build.xml
+
+# maven
+target/
+dependency-reduced-pom.xml
+
+# vim
+.*.sw[a-p]
+
+# various other potential build files
+build/
+bin/
+dist/
+manifest.mf
+
+# Mac filesystem dust
+.DS_Store/
+.DS_Store
+
+# intellij
+*.iml
+*.ipr
+*.iws
+.idea/
+
+working-dir/
diff --git a/README.md b/README.md
index 19f07bc..1fea526 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,3 @@
# FairFight
-d
+Fat quick anticheat to skid like agc
+Not shitty perm plugin needed no more
\ No newline at end of file
diff --git a/libs/ragespigot-1.8.8-R0.1-SNAPSHOT.jar b/libs/ragespigot-1.8.8-R0.1-SNAPSHOT.jar
new file mode 100644
index 0000000..0bb4072
Binary files /dev/null and b/libs/ragespigot-1.8.8-R0.1-SNAPSHOT.jar differ
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..4f39d36
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,77 @@
+
+
+ 4.0.0
+
+ me.joeleoli.fairfight
+ FairFight
+ 1.0-SNAPSHOT
+
+
+ 1.8
+ 1.8
+
+
+
+
+ me.joeleoli.ragespigot
+ ragespigot
+ 1.8.8-R0.1-SNAPSHOT
+ system
+ ${project.basedir}/libs/ragespigot-1.8.8-R0.1-SNAPSHOT.jar
+
+
+ com.google.code.gson
+ gson
+ 2.3.1
+ compile
+
+
+ org.projectlombok
+ lombok
+ 1.14.8
+ provided
+
+
+ redis.clients
+ jedis
+ 2.8.1
+ jar
+ compile
+
+
+ org.mongodb
+ mongodb-driver
+ LATEST
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ 1.8
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 2.1
+
+
+ package
+
+ shade
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/me/joeleoli/fairfight/FairFight.java b/src/main/java/me/joeleoli/fairfight/FairFight.java
new file mode 100644
index 0000000..6eee81e
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/FairFight.java
@@ -0,0 +1,91 @@
+package me.joeleoli.fairfight;
+
+
+import lombok.Getter;
+
+import me.joeleoli.fairfight.client.ClientManager;
+import me.joeleoli.fairfight.command.FairFightCommand;
+import me.joeleoli.fairfight.handler.CustomMovementHandler;
+import me.joeleoli.fairfight.handler.CustomPacketHandler;
+import me.joeleoli.fairfight.listener.BungeeListener;
+import me.joeleoli.fairfight.manager.PlayerDataManager;
+import me.joeleoli.fairfight.mongo.FairFightMongo;
+import me.joeleoli.fairfight.task.InsertLogsTask;
+
+import me.joeleoli.fairfight.util.nucleus.config.FileConfig;
+import me.joeleoli.fairfight.util.nucleus.listener.ListenerHandler;
+import me.joeleoli.ragespigot.RageSpigot;
+
+import net.minecraft.server.v1_8_R3.MinecraftServer;
+
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.java.JavaPlugin;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
+
+@Getter
+public class FairFight extends JavaPlugin {
+
+ @Getter
+ private static FairFight instance;
+
+ private FileConfig mainFileConfig;
+ private FairFightMongo mongo;
+ private PlayerDataManager playerDataManager;
+ private ClientManager clientManager;
+ private Set receivingAlerts;
+ private Set disabledChecks;
+ private double rangeVl;
+
+ public FairFight() {
+ this.rangeVl = 30.0;
+ }
+
+ public void onEnable() {
+ instance = this;
+
+ this.receivingAlerts = new HashSet<>();
+ this.disabledChecks = new HashSet<>();
+
+ this.mainFileConfig = new FileConfig(this, "config.yml");
+ this.mongo = new FairFightMongo();
+
+ RageSpigot.INSTANCE.addPacketHandler(new CustomPacketHandler(this));
+ RageSpigot.INSTANCE.addMovementHandler(new CustomMovementHandler(this));
+
+ getCommand("fairfight").setExecutor(new FairFightCommand());
+
+ ListenerHandler.loadListenersFromPackage(this, "me.joeleoli.fairfight.listener");
+
+ this.getServer().getMessenger().registerIncomingPluginChannel(this, "BungeeCord", new BungeeListener(this));
+ this.getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");
+
+ this.getServer().getScheduler().runTaskTimer(this, new InsertLogsTask(), 20L * 60L * 5L, 20L * 60L * 5L);
+
+ this.playerDataManager = new PlayerDataManager();
+ this.clientManager = new ClientManager();
+ }
+
+ public boolean isAntiCheatEnabled() {
+ return MinecraftServer.getServer().tps1.getAverage() > 19.0 && MinecraftServer.LAST_TICK_TIME + 100L > System.currentTimeMillis();
+ }
+
+ public boolean canAlert(Player player) {
+ return this.receivingAlerts.contains(player.getUniqueId());
+ }
+
+ public boolean toggleAlerts(Player player) {
+ boolean current = this.receivingAlerts.remove(player.getUniqueId());
+
+ if (!current) {
+ this.receivingAlerts.add(player.getUniqueId());
+ }
+
+ return !current;
+ }
+
+ private String oof = "This is the most bullshit thing I've ever made.";
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/AbstractCheck.java b/src/main/java/me/joeleoli/fairfight/check/AbstractCheck.java
new file mode 100644
index 0000000..7597fc5
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/AbstractCheck.java
@@ -0,0 +1,74 @@
+package me.joeleoli.fairfight.check;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import me.joeleoli.fairfight.FairFight;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import org.bukkit.entity.Player;
+
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.PlayerAlertEvent;
+import me.joeleoli.fairfight.event.player.PlayerBanEvent;
+
+@AllArgsConstructor
+@Getter
+public abstract class AbstractCheck implements ICheck {
+
+ protected final PlayerData playerData;
+ private final Class clazz;
+ private final String name;
+
+ @Override
+ public Class extends T> getType() {
+ return this.clazz;
+ }
+
+ protected FairFight getPlugin() {
+ return FairFight.getInstance();
+ }
+
+ protected double getVl() {
+ return this.playerData.getCheckVl(this);
+ }
+
+ protected void setVl(final double vl) {
+ this.playerData.setCheckVl(vl, this);
+ }
+
+ protected boolean alert(AlertType alertType, Player player, String extra, boolean violation) {
+ final PlayerAlertEvent event = new PlayerAlertEvent(alertType, player, this.name, extra);
+
+ this.getPlugin().getServer().getPluginManager().callEvent(event);
+
+ if (!event.isCancelled()) {
+ if (violation) {
+ this.playerData.addViolation(this);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ protected boolean ban(final Player player) {
+ this.playerData.setBanning(true);
+
+ final PlayerBanEvent event = new PlayerBanEvent(player, this.name);
+
+ this.getPlugin().getServer().getPluginManager().callEvent(event);
+
+ return !event.isCancelled();
+ }
+
+ protected void randomBan(Player player, double rate) {
+ this.playerData.setRandomBanRate(rate);
+ this.playerData.setRandomBanReason(this.name);
+ this.playerData.setRandomBan(true);
+
+ this.getPlugin().getServer().getPluginManager().callEvent(new PlayerAlertEvent(AlertType.RELEASE, player, this.name, null));
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/ICheck.java b/src/main/java/me/joeleoli/fairfight/check/ICheck.java
new file mode 100644
index 0000000..c61b9ee
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/ICheck.java
@@ -0,0 +1,11 @@
+package me.joeleoli.fairfight.check;
+
+import org.bukkit.entity.Player;
+
+public interface ICheck {
+
+ void handleCheck(Player player, T type);
+
+ Class extends T> getType();
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/checks/PacketCheck.java b/src/main/java/me/joeleoli/fairfight/check/checks/PacketCheck.java
new file mode 100644
index 0000000..3e23928
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/checks/PacketCheck.java
@@ -0,0 +1,13 @@
+package me.joeleoli.fairfight.check.checks;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import me.joeleoli.fairfight.check.AbstractCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+
+public abstract class PacketCheck extends AbstractCheck {
+
+ public PacketCheck(PlayerData playerData, final String name) {
+ super(playerData, Packet.class, name);
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/checks/PositionCheck.java b/src/main/java/me/joeleoli/fairfight/check/checks/PositionCheck.java
new file mode 100644
index 0000000..6b480c0
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/checks/PositionCheck.java
@@ -0,0 +1,13 @@
+package me.joeleoli.fairfight.check.checks;
+
+import me.joeleoli.fairfight.check.AbstractCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.util.update.PositionUpdate;
+
+public abstract class PositionCheck extends AbstractCheck {
+
+ public PositionCheck(PlayerData playerData, String name) {
+ super(playerData, PositionUpdate.class, name);
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/checks/RotationCheck.java b/src/main/java/me/joeleoli/fairfight/check/checks/RotationCheck.java
new file mode 100644
index 0000000..6fecdcc
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/checks/RotationCheck.java
@@ -0,0 +1,13 @@
+package me.joeleoli.fairfight.check.checks;
+
+import me.joeleoli.fairfight.check.AbstractCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.util.update.RotationUpdate;
+
+public abstract class RotationCheck extends AbstractCheck {
+
+ public RotationCheck(PlayerData playerData, String name) {
+ super(playerData, RotationUpdate.class, name);
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/aimassist/AimAssistA.java b/src/main/java/me/joeleoli/fairfight/check/impl/aimassist/AimAssistA.java
new file mode 100644
index 0000000..188b3d4
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/aimassist/AimAssistA.java
@@ -0,0 +1,41 @@
+package me.joeleoli.fairfight.check.impl.aimassist;
+
+import me.joeleoli.fairfight.check.checks.RotationCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.fairfight.util.MathUtil;
+import me.joeleoli.fairfight.util.update.RotationUpdate;
+import org.bukkit.entity.Player;
+
+public class AimAssistA extends RotationCheck {
+
+ private float suspiciousYaw;
+
+ public AimAssistA(PlayerData playerData) {
+ super(playerData, "Aim (Check 1)");
+ }
+
+ @Override
+ public void handleCheck(Player player, RotationUpdate update) {
+ if (System.currentTimeMillis() - this.playerData.getLastAttackPacket() > 10000L) {
+ return;
+ }
+
+ final float diffYaw = MathUtil.getDistanceBetweenAngles(update.getTo().getYaw(), update.getFrom().getYaw());
+
+ if (diffYaw > 1.0f && Math.round(diffYaw) == diffYaw && diffYaw % 1.5f != 0.0f) {
+ if (diffYaw == this.suspiciousYaw && this.alert(AlertType.RELEASE, player, "Y " + diffYaw + ".", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+
+ if (!this.playerData.isBanning() && violations > 20) {
+ this.ban(player);
+ }
+ }
+
+ this.suspiciousYaw = Math.round(diffYaw);
+ } else {
+ this.suspiciousYaw = 0.0f;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/aimassist/AimAssistB.java b/src/main/java/me/joeleoli/fairfight/check/impl/aimassist/AimAssistB.java
new file mode 100644
index 0000000..07fab36
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/aimassist/AimAssistB.java
@@ -0,0 +1,41 @@
+package me.joeleoli.fairfight.check.impl.aimassist;
+
+import me.joeleoli.fairfight.check.checks.RotationCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.fairfight.util.MathUtil;
+import me.joeleoli.fairfight.util.update.RotationUpdate;
+import org.bukkit.entity.Player;
+
+public class AimAssistB extends RotationCheck {
+
+ private float suspiciousYaw;
+
+ public AimAssistB(PlayerData playerData) {
+ super(playerData, "Aim (Check 2)");
+ }
+
+ @Override
+ public void handleCheck(Player player, RotationUpdate update) {
+ if (System.currentTimeMillis() - this.playerData.getLastAttackPacket() > 10000L) {
+ return;
+ }
+
+ final float diffYaw = MathUtil.getDistanceBetweenAngles(update.getTo().getYaw(), update.getFrom().getYaw());
+
+ if (diffYaw > 1.0f && Math.round(diffYaw * 10.0f) * 0.1f == diffYaw && Math.round(diffYaw) != diffYaw && diffYaw % 1.5f != 0.0f) {
+ if (diffYaw == this.suspiciousYaw && this.alert(AlertType.RELEASE, player, String.format("Y %.1f.", diffYaw), true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+
+ if (!this.playerData.isBanning() && violations > 20) {
+ this.ban(player);
+ }
+ }
+
+ this.suspiciousYaw = Math.round(diffYaw * 10.0f) * 0.1f;
+ } else {
+ this.suspiciousYaw = 0.0f;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/aimassist/AimAssistC.java b/src/main/java/me/joeleoli/fairfight/check/impl/aimassist/AimAssistC.java
new file mode 100644
index 0000000..7c54802
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/aimassist/AimAssistC.java
@@ -0,0 +1,37 @@
+package me.joeleoli.fairfight.check.impl.aimassist;
+
+import me.joeleoli.fairfight.check.checks.RotationCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.fairfight.util.MathUtil;
+import me.joeleoli.fairfight.util.update.RotationUpdate;
+
+import org.bukkit.entity.Player;
+
+public class AimAssistC extends RotationCheck {
+
+ public AimAssistC(PlayerData playerData) {
+ super(playerData, "Aim (Check 3)");
+ }
+
+ @Override
+ public void handleCheck(final Player player, final RotationUpdate update) {
+ if (System.currentTimeMillis() - this.playerData.getLastAttackPacket() > 10000L) {
+ return;
+ }
+
+ final float diffYaw = MathUtil.getDistanceBetweenAngles(update.getTo().getYaw(), update.getFrom().getYaw());
+ double vl = this.getVl();
+
+ if (update.getFrom().getPitch() == update.getTo().getPitch() && diffYaw >= 3.0f && update.getFrom().getPitch() != 90.0f && update.getTo().getPitch() != 90.0f) {
+ if ((vl += 0.9) >= 6.3) {
+ this.alert(AlertType.EXPERIMENTAL, player, String.format("Y %.1f. VL %.1f.", diffYaw, vl), false);
+ }
+ } else {
+ vl -= 1.6;
+ }
+
+ this.setVl(vl);
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/aimassist/AimAssistD.java b/src/main/java/me/joeleoli/fairfight/check/impl/aimassist/AimAssistD.java
new file mode 100644
index 0000000..a87b9b0
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/aimassist/AimAssistD.java
@@ -0,0 +1,49 @@
+package me.joeleoli.fairfight.check.impl.aimassist;
+
+import me.joeleoli.fairfight.check.checks.RotationCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.fairfight.util.MathUtil;
+import me.joeleoli.fairfight.util.update.RotationUpdate;
+import org.bukkit.entity.Player;
+
+public class AimAssistD extends RotationCheck {
+ private float lastYawRate;
+ private float lastPitchRate;
+
+ public AimAssistD(PlayerData playerData) {
+ super(playerData, "Aim (Check 4)");
+ }
+
+ @Override
+ public void handleCheck(final Player player, final RotationUpdate update) {
+ if (System.currentTimeMillis() - this.playerData.getLastAttackPacket() > 10000L) {
+ return;
+ }
+
+ float diffPitch = MathUtil.getDistanceBetweenAngles(update.getTo().getPitch(), update.getFrom().getPitch());
+ float diffYaw = MathUtil.getDistanceBetweenAngles(update.getTo().getYaw(), update.getFrom().getYaw());
+
+ float diffPitchRate = Math.abs(this.lastPitchRate - diffPitch);
+ float diffYawRate = Math.abs(this.lastYawRate - diffYaw);
+
+ float diffPitchRatePitch = Math.abs(diffPitchRate - diffPitch);
+ float diffYawRateYaw = Math.abs(diffYawRate - diffYaw);
+
+ if (diffPitch < 0.009 && diffPitch > 0.001 && diffPitchRate > 1.0 && diffYawRate > 1.0 && diffYaw > 3.0 &&
+ this.lastYawRate > 1.5 && (diffPitchRatePitch > 1.0f || diffYawRateYaw > 1.0f)) {
+ this.alert(AlertType.EXPERIMENTAL, player,
+ String.format("DPR %.3f. DYR %.3f. LPR %.3f. LYR %.3f. DP %.3f. DY %.2f. DPRP %.3f. DYRY %.3f.",
+ diffPitchRate, diffYawRate, this.lastPitchRate, this.lastYawRate, diffPitch, diffYaw,
+ diffPitchRatePitch, diffYawRateYaw), true);
+
+ if (!this.playerData.isBanning() && this.playerData.getViolations(this, 1000L * 60 * 10) > 5) {
+ this.ban(player);
+ }
+ }
+
+ this.lastPitchRate = diffPitch;
+ this.lastYawRate = diffYaw;
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/aimassist/AimAssistE.java b/src/main/java/me/joeleoli/fairfight/check/impl/aimassist/AimAssistE.java
new file mode 100644
index 0000000..4432242
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/aimassist/AimAssistE.java
@@ -0,0 +1,49 @@
+package me.joeleoli.fairfight.check.impl.aimassist;
+
+import me.joeleoli.fairfight.check.checks.RotationCheck;
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.fairfight.util.MathUtil;
+import org.bukkit.entity.Player;
+import me.joeleoli.fairfight.FairFight;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.util.update.RotationUpdate;
+
+public class AimAssistE extends RotationCheck {
+
+ private float lastPitchRate;
+ private float lastYawRate;
+
+ public AimAssistE(PlayerData playerData) {
+ super(playerData, "Aim (Check 5)");
+ }
+
+ @Override
+ public void handleCheck(Player player, RotationUpdate update) {
+ if (System.currentTimeMillis() - this.playerData.getLastAttackPacket() > 10000L) {
+ return;
+ }
+
+ float diffPitch = MathUtil.getDistanceBetweenAngles(update.getTo().getPitch(), update.getFrom().getPitch());
+ float diffYaw = MathUtil.getDistanceBetweenAngles(update.getTo().getYaw(), update.getFrom().getYaw());
+
+ float diffYawPitch = Math.abs(diffYaw - diffPitch);
+
+ float diffPitchRate = Math.abs(this.lastPitchRate - diffPitch);
+ float diffYawRate = Math.abs(this.lastYawRate - diffYaw);
+
+ float diffPitchRatePitch = Math.abs(diffPitchRate - diffPitch);
+ float diffYawRateYaw = Math.abs(diffYawRate - diffYaw);
+
+ if (diffYaw > 0.05f && diffPitch > 0.05 && (diffPitchRate > 1.0 || diffYawRate > 1.0) &&
+ (diffPitchRatePitch > 1.0f || diffYawRateYaw > 1.0f) && diffYawPitch < 0.009f && diffYawPitch > 0.001f) {
+ this.alert(AlertType.EXPERIMENTAL, player,
+ String.format("DYP %.3f. DP %.3f. DY %.3f. DPR %.3f. DYR %.3f. DPRP %.3f. DYRY %.3f.",
+ diffYawPitch, diffYaw, diffPitch, diffPitchRate, diffYawRate,
+ diffPitchRatePitch, diffYawRateYaw), false);
+ }
+
+ this.lastYawRate = diffYaw;
+ this.lastPitchRate = diffPitch;
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerA.java b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerA.java
new file mode 100644
index 0000000..c406c29
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerA.java
@@ -0,0 +1,45 @@
+package me.joeleoli.fairfight.check.impl.autoclicker;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.event.player.AlertType;
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInArmAnimation;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+
+import org.bukkit.entity.Player;
+
+import me.joeleoli.fairfight.player.PlayerData;
+
+public class AutoClickerA extends PacketCheck {
+
+ private int swings;
+ private int movements;
+
+ public AutoClickerA(PlayerData playerData) {
+ super(playerData, "Auto-Clicker (Check 1)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInArmAnimation
+ && !this.playerData.isDigging() && !this.playerData.isPlacing() && !this.playerData.isFakeDigging()
+ && (System.currentTimeMillis() - this.playerData.getLastDelayedMovePacket()) > 220L
+ && (System.currentTimeMillis() - this.playerData.getLastMovePacket().getTimestamp()) < 110L) {
+ ++this.swings;
+ } else if (packet instanceof PacketPlayInFlying && ++this.movements == 20) {
+ if (this.swings > 20 &&
+ this.alert(AlertType.RELEASE, player, "C " + this.swings + ".", true)) {
+
+ int violations = this.playerData.getViolations(this, 60000L);
+
+ if (!this.playerData.isBanning() && violations > 3) {
+ this.ban(player);
+ }
+ }
+
+ this.playerData.setLastCps(this.swings);
+ this.movements = this.swings = 0;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerB.java b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerB.java
new file mode 100644
index 0000000..9980b6c
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerB.java
@@ -0,0 +1,72 @@
+package me.joeleoli.fairfight.check.impl.autoclicker;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.event.player.AlertType;
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInArmAnimation;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockDig;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+
+import org.bukkit.entity.Player;
+
+import me.joeleoli.fairfight.player.PlayerData;
+
+public class AutoClickerB extends PacketCheck {
+
+ private int clicks;
+ private int outliers;
+ private int flyingCount;
+ private boolean release;
+
+ public AutoClickerB(PlayerData playerData) {
+ super(playerData, "Auto-Clicker (Check 2)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInArmAnimation && !this.playerData.isDigging() &&
+ !this.playerData.isPlacing() &&
+ System.currentTimeMillis() - this.playerData.getLastDelayedMovePacket() > 220L &&
+ this.playerData.getLastMovePacket() != null &&
+ System.currentTimeMillis() - this.playerData.getLastMovePacket().getTimestamp() < 110L &&
+ !this.playerData.isFakeDigging()) {
+
+ if (this.flyingCount < 10) {
+ if (this.release) {
+ this.release = false;
+ this.flyingCount = 0;
+ return;
+ }
+
+ if (this.flyingCount > 3) {
+ ++this.outliers;
+ } else if (this.flyingCount == 0) {
+ return;
+ }
+
+ if (++this.clicks == 1000) {
+ double vl = this.getVl();
+
+ if (this.outliers <= 7) {
+ if ((vl += 1.4) >= 4.0) {
+ this.alert(AlertType.DEVELOPMENT, player, String.format("O %s. VL %.2f.", this.outliers, vl), false);
+ }
+ } else {
+ vl -= 0.8;
+ }
+
+ this.setVl(vl);
+ final boolean b = false;
+ this.outliers = (b ? 1 : 0);
+ this.clicks = (b ? 1 : 0);
+ }
+ }
+ this.flyingCount = 0;
+ } else if (packet instanceof PacketPlayInFlying) {
+ ++this.flyingCount;
+ } else if (packet instanceof PacketPlayInBlockDig && ((PacketPlayInBlockDig) packet).c() == PacketPlayInBlockDig.EnumPlayerDigType.RELEASE_USE_ITEM) {
+ this.release = true;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerC.java b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerC.java
new file mode 100644
index 0000000..ca43c67
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerC.java
@@ -0,0 +1,46 @@
+package me.joeleoli.fairfight.check.impl.autoclicker;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInArmAnimation;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockDig;
+
+import org.bukkit.entity.Player;
+
+public class AutoClickerC extends PacketCheck {
+
+ private boolean sent;
+
+ public AutoClickerC(PlayerData playerData) {
+ super(playerData, "Auto-Clicker (Check 3)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInBlockDig) {
+ final PacketPlayInBlockDig.EnumPlayerDigType digType = ((PacketPlayInBlockDig) packet).c();
+
+ if (digType == PacketPlayInBlockDig.EnumPlayerDigType.START_DESTROY_BLOCK) {
+ this.sent = true;
+ } else if (digType == PacketPlayInBlockDig.EnumPlayerDigType.ABORT_DESTROY_BLOCK) {
+ int vl = (int) this.getVl();
+
+ if (this.sent) {
+ if (++vl > 10 && this.alert(AlertType.RELEASE, player, "VL " + vl + ".", false) && !this.playerData.isBanning() && !this.playerData.isRandomBan() && vl >= 20) {
+ this.randomBan(player, 250.0);
+ }
+ } else {
+ vl = 0;
+ }
+
+ this.setVl(vl);
+ }
+ } else if (packet instanceof PacketPlayInArmAnimation) {
+ this.sent = false;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerD.java b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerD.java
new file mode 100644
index 0000000..f1ceb61
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerD.java
@@ -0,0 +1,88 @@
+package me.joeleoli.fairfight.check.impl.autoclicker;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInArmAnimation;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockDig;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+
+import org.bukkit.entity.Player;
+
+public class AutoClickerD extends PacketCheck {
+
+ private int movements;
+ private int stage;
+
+ public AutoClickerD(PlayerData playerData) {
+ super(playerData, "Auto-Clicker (Check 4)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ int vl = (int) this.getVl();
+
+ if (this.stage == 0) {
+ if (packet instanceof PacketPlayInArmAnimation) {
+ ++this.stage;
+ }
+ } else if (this.stage == 1) {
+ if (packet instanceof PacketPlayInBlockDig && ((PacketPlayInBlockDig) packet).c() == PacketPlayInBlockDig.EnumPlayerDigType.START_DESTROY_BLOCK) {
+ ++this.stage;
+ } else {
+ this.stage = 0;
+ }
+ } else if (this.stage == 2) {
+ if (packet instanceof PacketPlayInBlockDig && ((PacketPlayInBlockDig) packet).c() == PacketPlayInBlockDig.EnumPlayerDigType.ABORT_DESTROY_BLOCK) {
+ if (++vl >= 5) {
+ try {
+ if (this.movements > 10 && this.alert(AlertType.RELEASE, player, "M " + this.movements + ".", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+
+ if (!this.playerData.isBanning() && !this.playerData.isRandomBan() && violations > 4) {
+ this.randomBan(player, 250.0);
+ }
+ }
+ } finally {
+ final boolean movements = false;
+ this.movements = (movements ? 1 : 0);
+ vl = (movements ? 1 : 0);
+ }
+ }
+
+ this.stage = 0;
+ } else if (packet instanceof PacketPlayInArmAnimation) {
+ ++this.stage;
+ } else {
+ final boolean b = false;
+ this.movements = (b ? 1 : 0);
+ vl = (b ? 1 : 0);
+ this.stage = (b ? 1 : 0);
+ }
+ } else if (this.stage == 3) {
+ if (packet instanceof PacketPlayInFlying) {
+ ++this.stage;
+ } else {
+ final boolean b2 = false;
+ this.movements = (b2 ? 1 : 0);
+ vl = (b2 ? 1 : 0);
+ this.stage = (b2 ? 1 : 0);
+ }
+ } else if (this.stage == 4) {
+ if (packet instanceof PacketPlayInBlockDig && ((PacketPlayInBlockDig) packet).c() == PacketPlayInBlockDig.EnumPlayerDigType.ABORT_DESTROY_BLOCK) {
+ ++this.movements;
+
+ this.stage = 0;
+ } else {
+ final boolean b3 = false;
+ this.movements = (b3 ? 1 : 0);
+ vl = (b3 ? 1 : 0);
+ this.stage = (b3 ? 1 : 0);
+ }
+ }
+
+ this.setVl(vl);
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerE.java b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerE.java
new file mode 100644
index 0000000..ad945bc
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerE.java
@@ -0,0 +1,54 @@
+package me.joeleoli.fairfight.check.impl.autoclicker;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInArmAnimation;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+
+import org.bukkit.entity.Player;
+
+public class AutoClickerE extends PacketCheck {
+
+ private boolean failed;
+ private boolean sent;
+ private int count;
+
+ public AutoClickerE(PlayerData playerData) {
+ super(playerData, "Auto-Clicker (Check 5)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInArmAnimation
+ && (System.currentTimeMillis() - this.playerData.getLastDelayedMovePacket()) > 220L
+ && (System.currentTimeMillis() - this.playerData.getLastMovePacket().getTimestamp()) < 110L
+ && !this.playerData.isDigging() && !this.playerData.isPlacing() && !this.playerData.isFakeDigging()) {
+ if (this.sent) {
+ ++this.count;
+
+ if (!this.failed) {
+ int vl = (int) this.getVl();
+
+ if (++vl >= 5) {
+ this.alert(AlertType.EXPERIMENTAL, player, "CO " + this.count + ".", false);
+ vl = 0;
+ }
+
+ this.setVl(vl);
+ this.failed = true;
+ }
+ } else {
+ this.sent = true;
+ this.count = 0;
+ }
+ } else if (packet instanceof PacketPlayInFlying) {
+ final boolean b = false;
+ this.failed = b;
+ this.sent = b;
+ this.count = 0;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerF.java b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerF.java
new file mode 100644
index 0000000..51678b4
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerF.java
@@ -0,0 +1,70 @@
+package me.joeleoli.fairfight.check.impl.autoclicker;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.event.player.AlertType;
+import net.minecraft.server.v1_8_R3.BlockPosition;
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockDig;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+
+import org.bukkit.entity.Player;
+
+import me.joeleoli.fairfight.player.PlayerData;
+
+import java.util.Deque;
+import java.util.LinkedList;
+
+public class AutoClickerF extends PacketCheck {
+
+ private final Deque recentCounts;
+ private BlockPosition lastBlock;
+ private int flyingCount;
+
+ public AutoClickerF(PlayerData playerData) {
+ super(playerData, "Auto-Clicker (Check 6)");
+ this.recentCounts = new LinkedList<>();
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInBlockDig) {
+ final PacketPlayInBlockDig blockDig = (PacketPlayInBlockDig) packet;
+ if (blockDig.c() == PacketPlayInBlockDig.EnumPlayerDigType.START_DESTROY_BLOCK) {
+ if (this.lastBlock != null && this.lastBlock.equals(blockDig.a())) {
+ double vl = this.getVl();
+ this.recentCounts.addLast(this.flyingCount);
+ if (this.recentCounts.size() == 20) {
+ double average = 0.0;
+ for (final int i : this.recentCounts) {
+ average += i;
+ }
+ average /= this.recentCounts.size();
+ double stdDev = 0.0;
+ for (final int j : this.recentCounts) {
+ stdDev += Math.pow(j - average, 2.0);
+ }
+ stdDev /= this.recentCounts.size();
+ stdDev = Math.sqrt(stdDev);
+ if (stdDev < 0.45 && ++vl >= 3.0) {
+ if (this.alert(AlertType.RELEASE, player, String.format("STD %.2f. VL " +
+ "%.1f.", stdDev, vl), false) && !this.playerData.isBanning() && !this.playerData
+ .isRandomBan() && vl >= 6.0) {
+ this.randomBan(player, 200.0);
+ }
+ } else {
+ vl -= 0.5;
+ }
+ this.recentCounts.clear();
+ }
+ this.setVl(vl);
+ }
+ this.flyingCount = 0;
+ } else if (blockDig.c() == PacketPlayInBlockDig.EnumPlayerDigType.ABORT_DESTROY_BLOCK) {
+ this.lastBlock = blockDig.a();
+ }
+ } else if (packet instanceof PacketPlayInFlying) {
+ ++this.flyingCount;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerG.java b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerG.java
new file mode 100644
index 0000000..5f01bc7
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerG.java
@@ -0,0 +1,44 @@
+package me.joeleoli.fairfight.check.impl.autoclicker;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockPlace;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+
+import org.bukkit.entity.Player;
+
+public class AutoClickerG extends PacketCheck {
+
+ private boolean failed;
+ private boolean sent;
+
+ public AutoClickerG(PlayerData playerData) {
+ super(playerData, "Auto-Clicker (Check 7)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInBlockPlace && ((PacketPlayInBlockPlace) packet).getFace() == 255 && System
+ .currentTimeMillis() - this.playerData.getLastDelayedMovePacket() > 220L && this.playerData
+ .getLastMovePacket() != null && System.currentTimeMillis() - this.playerData.getLastMovePacket()
+ .getTimestamp() < 110L && this.playerData.getLastAnimationPacket() + 1000L > System.currentTimeMillis
+ ()) {
+ if (this.sent) {
+ if (!this.failed) {
+ this.alert(AlertType.EXPERIMENTAL, player, "", false);
+ this.failed = true;
+ }
+ } else {
+ this.sent = true;
+ }
+ } else if (packet instanceof PacketPlayInFlying) {
+ final boolean b = false;
+ this.failed = b;
+ this.sent = b;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerH.java b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerH.java
new file mode 100644
index 0000000..c15ff9d
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerH.java
@@ -0,0 +1,73 @@
+package me.joeleoli.fairfight.check.impl.autoclicker;
+
+import java.util.Deque;
+import java.util.LinkedList;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInArmAnimation;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockDig;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+import org.bukkit.entity.Player;
+
+public class AutoClickerH extends PacketCheck {
+ private final Deque recentCounts;
+ private int flyingCount;
+ private boolean release;
+
+ public AutoClickerH(PlayerData playerData) {
+ super(playerData, "Auto-Clicker (Check 8)");
+ this.recentCounts = new LinkedList();
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInArmAnimation && !this.playerData.isDigging() &&
+ !this.playerData.isPlacing() &&
+ System.currentTimeMillis() - this.playerData.getLastDelayedMovePacket() > 220L &&
+ this.playerData.getLastMovePacket() != null &&
+ System.currentTimeMillis() - this.playerData.getLastMovePacket().getTimestamp() < 110L &&
+ !this.playerData.isFakeDigging()) {
+ if (this.flyingCount < 10) {
+ if (this.release) {
+ this.release = false;
+ this.flyingCount = 0;
+ return;
+ }
+ this.recentCounts.add(this.flyingCount);
+ if (this.recentCounts.size() == 100) {
+ double average = 0.0;
+ for (final int i : this.recentCounts) {
+ average += i;
+ }
+ average /= this.recentCounts.size();
+ double stdDev = 0.0;
+ for (final int j : this.recentCounts) {
+ stdDev += Math.pow(j - average, 2.0);
+ }
+ stdDev /= this.recentCounts.size();
+ stdDev = Math.sqrt(stdDev);
+ double vl = this.getVl();
+ if (stdDev < 0.45) {
+ if ((vl += 1.4) >= 4.0) {
+ this.alert(AlertType.EXPERIMENTAL, player,
+ String.format("STD %.2f. VL %.2f.", stdDev, vl), false);
+ }
+ } else {
+ vl -= 0.8;
+ }
+ this.setVl(vl);
+ this.recentCounts.clear();
+ }
+ }
+ this.flyingCount = 0;
+ } else if (packet instanceof PacketPlayInFlying) {
+ ++this.flyingCount;
+ } else if (packet instanceof PacketPlayInBlockDig &&
+ ((PacketPlayInBlockDig) packet).c() == PacketPlayInBlockDig.EnumPlayerDigType.RELEASE_USE_ITEM) {
+ this.release = true;
+ }
+ }
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerI.java b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerI.java
new file mode 100644
index 0000000..3acd611
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerI.java
@@ -0,0 +1,65 @@
+package me.joeleoli.fairfight.check.impl.autoclicker;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockDig;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockPlace;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+
+import org.bukkit.entity.Player;
+
+import java.util.Deque;
+import java.util.LinkedList;
+
+public class AutoClickerI extends PacketCheck {
+
+ private final Deque recentCounts;
+ private int flyingCount;
+
+ public AutoClickerI(PlayerData playerData) {
+ super(playerData, "Auto-Clicker (Check 9)");
+ this.recentCounts = new LinkedList<>();
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInBlockDig && ((PacketPlayInBlockDig) packet).c() == PacketPlayInBlockDig.EnumPlayerDigType.RELEASE_USE_ITEM) {
+ if (this.flyingCount < 10 && this.playerData.getLastAnimationPacket() + 2000L > System.currentTimeMillis()) {
+ this.recentCounts.add(this.flyingCount);
+ if (this.recentCounts.size() == 100) {
+ double average = 0.0;
+ for (final double flyingCount : this.recentCounts) {
+ average += flyingCount;
+ }
+ average /= this.recentCounts.size();
+ double stdDev = 0.0;
+ for (final long l : this.recentCounts) {
+ stdDev += Math.pow(l - average, 2.0);
+ }
+ stdDev /= this.recentCounts.size();
+ stdDev = Math.sqrt(stdDev);
+ double vl = this.getVl();
+ if (stdDev < 0.2) {
+ if ((vl += 1.4) >= 4.0) {
+ this.alert(AlertType.EXPERIMENTAL, player, String.format("STD %.2f. VL %.2f.", stdDev,
+ vl), false);
+ }
+ } else {
+ vl -= 0.8;
+ }
+ this.setVl(vl);
+ this.recentCounts.clear();
+ }
+ }
+ } else if (packet instanceof PacketPlayInBlockPlace && ((PacketPlayInBlockPlace) packet).getItemStack() !=
+ null && ((PacketPlayInBlockPlace) packet).getItemStack().getName().toLowerCase().contains("sword")) {
+ this.flyingCount = 0;
+ } else if (packet instanceof PacketPlayInFlying) {
+ ++this.flyingCount;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerJ.java b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerJ.java
new file mode 100644
index 0000000..ef8639b
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerJ.java
@@ -0,0 +1,57 @@
+package me.joeleoli.fairfight.check.impl.autoclicker;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInArmAnimation;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockDig;
+import org.bukkit.entity.Player;
+
+public class AutoClickerJ extends PacketCheck {
+ private int stage;
+
+ public AutoClickerJ(PlayerData playerData) {
+ super(playerData, "Auto-Clicker (Check 10)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (this.stage == 0) {
+ if (packet instanceof PacketPlayInArmAnimation) {
+ ++this.stage;
+ }
+ } else if (packet instanceof PacketPlayInBlockDig) {
+ if (this.playerData.getFakeBlocks().contains(((PacketPlayInBlockDig) packet).a())) {
+ return;
+ }
+
+ double vl = this.getVl();
+
+ PacketPlayInBlockDig.EnumPlayerDigType digType = ((PacketPlayInBlockDig) packet).c();
+ if (digType == PacketPlayInBlockDig.EnumPlayerDigType.ABORT_DESTROY_BLOCK) {
+ if (this.stage == 1) {
+ ++this.stage;
+ } else {
+ this.stage = 0;
+ }
+ } else if (digType == PacketPlayInBlockDig.EnumPlayerDigType.START_DESTROY_BLOCK) {
+ if (this.stage == 2) {
+ if ((vl += 1.4) >= 15.0 &&
+ this.alert(AlertType.RELEASE, player, String.format("VL %.2f.", vl), true) &&
+ !this.playerData.isBanning() && !this.playerData.isRandomBan() && vl >= 50.0) {
+ this.randomBan(player, 250.0);
+ }
+ } else {
+ this.stage = 0;
+ vl -= 0.25;
+ }
+ } else {
+ this.stage = 0;
+ }
+ this.setVl(vl);
+ } else {
+ this.stage = 0;
+ }
+ }
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerK.java b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerK.java
new file mode 100644
index 0000000..3c95007
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerK.java
@@ -0,0 +1,104 @@
+package me.joeleoli.fairfight.check.impl.autoclicker;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInArmAnimation;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockDig;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+
+import org.bukkit.entity.Player;
+
+public class AutoClickerK extends PacketCheck {
+
+ private int stage;
+ private boolean other;
+
+ public AutoClickerK(PlayerData playerData) {
+ super(playerData, "Auto-Clicker (Check 11)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (this.stage == 0) {
+ if (packet instanceof PacketPlayInBlockDig && ((PacketPlayInBlockDig)packet).c() == PacketPlayInBlockDig.EnumPlayerDigType.START_DESTROY_BLOCK) {
+ ++this.stage;
+ }
+ } else if (this.stage == 1) {
+ if (packet instanceof PacketPlayInArmAnimation) {
+ ++this.stage;
+ } else {
+ this.stage = 0;
+ }
+ } else if (this.stage == 2) {
+ if (packet instanceof PacketPlayInFlying) {
+ ++this.stage;
+ } else {
+ this.stage = 0;
+ }
+ } else if (this.stage == 3) {
+ if (packet instanceof PacketPlayInArmAnimation) {
+ ++this.stage;
+ } else {
+ this.stage = 0;
+ }
+ } else if (this.stage == 4) {
+ if (packet instanceof PacketPlayInFlying) {
+ ++this.stage;
+ } else {
+ this.stage = 0;
+ }
+ } else if (this.stage == 5) {
+ if (packet instanceof PacketPlayInBlockDig && ((PacketPlayInBlockDig)packet).c() == PacketPlayInBlockDig.EnumPlayerDigType.START_DESTROY_BLOCK) {
+ if (this.alert(AlertType.EXPERIMENTAL, player, "", false)) {
+ this.checkBan(player);
+ }
+
+ this.stage = 0;
+ } else if (packet instanceof PacketPlayInArmAnimation) {
+ ++this.stage;
+ } else if (packet instanceof PacketPlayInFlying) {
+ this.other = true;
+ ++this.stage;
+ } else {
+ this.stage = 0;
+ }
+ } else if (this.stage == 6) {
+ if (!this.other) {
+ if (packet instanceof PacketPlayInFlying) {
+ ++this.stage;
+ } else {
+ this.stage = 0;
+ }
+ } else {
+ if (packet instanceof PacketPlayInBlockDig && ((PacketPlayInBlockDig)packet).c() == PacketPlayInBlockDig.EnumPlayerDigType.START_DESTROY_BLOCK) {
+ if (this.alert(AlertType.EXPERIMENTAL, player, "Type B.", false)) {
+ this.checkBan(player);
+ }
+
+ this.other = false;
+ }
+
+ this.stage = 0;
+ }
+ } else if (this.stage == 7) {
+ if (packet instanceof PacketPlayInBlockDig && ((PacketPlayInBlockDig)packet).c() == PacketPlayInBlockDig.EnumPlayerDigType.START_DESTROY_BLOCK) {
+ if (this.alert(AlertType.EXPERIMENTAL, player, "Type C.", false)) {
+ this.checkBan(player);
+ }
+ } else {
+ this.stage = 0;
+ }
+ }
+ }
+
+ private void checkBan(final Player player) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+
+ if (!this.playerData.isBanning() && violations > 2) {
+ this.ban(player);
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerL.java b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerL.java
new file mode 100644
index 0000000..680383e
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/autoclicker/AutoClickerL.java
@@ -0,0 +1,72 @@
+package me.joeleoli.fairfight.check.impl.autoclicker;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInArmAnimation;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockDig;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+
+import org.bukkit.entity.Player;
+
+public class AutoClickerL extends PacketCheck {
+
+ private int movements;
+ private int failed;
+ private int passed;
+ private int stage;
+
+ public AutoClickerL(PlayerData playerData) {
+ super(playerData, "Auto-Clicker (Check 12)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (System.currentTimeMillis() - this.playerData.getLastDelayedMovePacket() > 220L && this.playerData.getLastMovePacket() != null && System.currentTimeMillis() - this.playerData.getLastMovePacket().getTimestamp() < 110L) {
+ if (packet instanceof PacketPlayInArmAnimation) {
+ if (this.stage == 0 || this.stage == 1) {
+ ++this.stage;
+ } else {
+ this.stage = 1;
+ }
+ } else if (packet instanceof PacketPlayInFlying) {
+ if (this.stage == 2) {
+ ++this.stage;
+ } else {
+ this.stage = 0;
+ }
+ ++this.movements;
+ } else if (packet instanceof PacketPlayInBlockDig && ((PacketPlayInBlockDig) packet).c() == PacketPlayInBlockDig.EnumPlayerDigType.ABORT_DESTROY_BLOCK) {
+ if (this.stage == 3) {
+ ++this.failed;
+ } else {
+ ++this.passed;
+ }
+ if (this.movements >= 200 && this.failed + this.passed > 60) {
+ final double rat = (this.passed == 0) ? -1.0 : (this.failed / this.passed);
+ double vl = this.getVl();
+
+ if (rat > 2.5) {
+ if ((vl += 1.0 + (rat - 2.0) * 0.75) >= 4.0) {
+ this.alert(AlertType.EXPERIMENTAL, player, String.format("RAT %.2f. VL %.2f.", rat, vl), false);
+ }
+ } else {
+ vl -= 2.0;
+ }
+
+ this.setVl(vl);
+
+ final boolean failed = false;
+ this.movements = (failed ? 1 : 0);
+ this.passed = (failed ? 1 : 0);
+ this.failed = (failed ? 1 : 0);
+ }
+ }
+ } else {
+ this.stage = 0;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsA.java b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsA.java
new file mode 100644
index 0000000..1ff6507
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsA.java
@@ -0,0 +1,35 @@
+package me.joeleoli.fairfight.check.impl.badpackets;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+import net.minecraft.server.v1_8_R3.PacketPlayInSteerVehicle;
+
+import org.bukkit.entity.Player;
+
+public class BadPacketsA extends PacketCheck {
+
+ private int streak;
+
+ public BadPacketsA(PlayerData playerData) {
+ super(playerData, "Packets (Check 1)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInFlying) {
+ if (((PacketPlayInFlying) packet).g()) {
+ this.streak = 0;
+ } else if (++this.streak > 20 && this.alert(AlertType.RELEASE, player, "", false) && !this.playerData
+ .isBanning()) {
+ this.ban(player);
+ }
+ } else if (packet instanceof PacketPlayInSteerVehicle) {
+ this.streak = 0;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsB.java b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsB.java
new file mode 100644
index 0000000..52b7560
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsB.java
@@ -0,0 +1,27 @@
+package me.joeleoli.fairfight.check.impl.badpackets;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+
+import org.bukkit.entity.Player;
+
+public class BadPacketsB extends PacketCheck {
+
+ public BadPacketsB(PlayerData playerData) {
+ super(playerData, "Packets (Check 2)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInFlying && Math.abs(((PacketPlayInFlying) packet).e()) > 90.0f && this.alert
+ (AlertType.RELEASE, player, "", false) && !this.playerData.isBanning() && !this.playerData
+ .isRandomBan()) {
+ this.randomBan(player, 200.0);
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsC.java b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsC.java
new file mode 100644
index 0000000..b268491
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsC.java
@@ -0,0 +1,44 @@
+package me.joeleoli.fairfight.check.impl.badpackets;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInEntityAction;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+
+import org.bukkit.entity.Player;
+
+public class BadPacketsC extends PacketCheck {
+
+ private boolean sent;
+
+ public BadPacketsC(PlayerData playerData) {
+ super(playerData, "Packets (Check 3)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInEntityAction) {
+ final PacketPlayInEntityAction.EnumPlayerAction playerAction = ((PacketPlayInEntityAction) packet).b();
+
+ if (playerAction == PacketPlayInEntityAction.EnumPlayerAction.START_SPRINTING || playerAction == PacketPlayInEntityAction.EnumPlayerAction.STOP_SPRINTING) {
+ if (this.sent) {
+ if (this.alert(AlertType.RELEASE, player, "", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+
+ if (!this.playerData.isBanning() && violations > 2) {
+ this.ban(player);
+ }
+ }
+ } else {
+ this.sent = true;
+ }
+ }
+ } else if (packet instanceof PacketPlayInFlying) {
+ this.sent = false;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsD.java b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsD.java
new file mode 100644
index 0000000..7ff05f3
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsD.java
@@ -0,0 +1,43 @@
+package me.joeleoli.fairfight.check.impl.badpackets;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInEntityAction;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+
+import org.bukkit.entity.Player;
+
+public class BadPacketsD extends PacketCheck {
+
+ private boolean sent;
+
+ public BadPacketsD(PlayerData playerData) {
+ super(playerData, "Packets (Check 4)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInEntityAction) {
+ final PacketPlayInEntityAction.EnumPlayerAction playerAction = ((PacketPlayInEntityAction) packet).b();
+ if (playerAction == PacketPlayInEntityAction.EnumPlayerAction.START_SNEAKING || playerAction ==
+ PacketPlayInEntityAction.EnumPlayerAction.STOP_SNEAKING) {
+ if (this.sent) {
+ if (this.alert(AlertType.RELEASE, player, "", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+ if (!this.playerData.isBanning() && violations > 2) {
+ this.ban(player);
+ }
+ }
+ } else {
+ this.sent = true;
+ }
+ }
+ } else if (packet instanceof PacketPlayInFlying) {
+ this.sent = false;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsE.java b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsE.java
new file mode 100644
index 0000000..f311dee
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsE.java
@@ -0,0 +1,29 @@
+package me.joeleoli.fairfight.check.impl.badpackets;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockDig;
+
+import org.bukkit.entity.Player;
+
+public class BadPacketsE extends PacketCheck {
+
+ public BadPacketsE(PlayerData playerData) {
+ super(playerData, "Packets (Check 5)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInBlockDig && ((PacketPlayInBlockDig) packet).c() == PacketPlayInBlockDig.EnumPlayerDigType.RELEASE_USE_ITEM && this.playerData.isPlacing() && this.alert(AlertType.RELEASE, player, "", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+
+ if (!this.playerData.isBanning() && violations > 2) {
+ this.ban(player);
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsF.java b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsF.java
new file mode 100644
index 0000000..15cd3be
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsF.java
@@ -0,0 +1,39 @@
+package me.joeleoli.fairfight.check.impl.badpackets;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockPlace;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+import net.minecraft.server.v1_8_R3.PacketPlayInHeldItemSlot;
+
+import org.bukkit.entity.Player;
+
+public class BadPacketsF extends PacketCheck {
+
+ private boolean sent;
+
+ public BadPacketsF(PlayerData playerData) {
+ super(playerData, "Packets (Check 6)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInHeldItemSlot) {
+ if (this.sent && this.alert(AlertType.RELEASE, player, "", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+
+ if (!this.playerData.isBanning() && violations > 2) {
+ this.ban(player);
+ }
+ }
+ } else if (packet instanceof PacketPlayInBlockPlace) {
+ this.sent = true;
+ } else if (packet instanceof PacketPlayInFlying) {
+ this.sent = false;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsG.java b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsG.java
new file mode 100644
index 0000000..0f17a60
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsG.java
@@ -0,0 +1,39 @@
+package me.joeleoli.fairfight.check.impl.badpackets;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInEntityAction;
+
+import org.bukkit.entity.Player;
+
+public class BadPacketsG extends PacketCheck {
+
+ private PacketPlayInEntityAction.EnumPlayerAction lastAction;
+
+ public BadPacketsG(PlayerData playerData) {
+ super(playerData, "Packets (Check 7)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInEntityAction) {
+ final PacketPlayInEntityAction.EnumPlayerAction playerAction = ((PacketPlayInEntityAction) packet).b();
+
+ if (playerAction == PacketPlayInEntityAction.EnumPlayerAction.START_SPRINTING || playerAction == PacketPlayInEntityAction.EnumPlayerAction.STOP_SPRINTING) {
+ if (this.lastAction == playerAction && this.playerData.getLastAttackPacket() + 10000L > System.currentTimeMillis() && this.alert(AlertType.RELEASE, player, "", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+
+ if (!this.playerData.isBanning() && violations > 2) {
+ this.ban(player);
+ }
+ }
+
+ this.lastAction = playerAction;
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsH.java b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsH.java
new file mode 100644
index 0000000..bf67238
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsH.java
@@ -0,0 +1,39 @@
+package me.joeleoli.fairfight.check.impl.badpackets;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInHeldItemSlot;
+
+import org.bukkit.entity.Player;
+
+public class BadPacketsH extends PacketCheck {
+
+ private int lastSlot;
+
+ public BadPacketsH(PlayerData playerData) {
+ super(playerData, "Packets (Check 8)");
+
+ this.lastSlot = -1;
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInHeldItemSlot) {
+ final int slot = ((PacketPlayInHeldItemSlot) packet).a();
+
+ if (this.lastSlot == slot && this.alert(AlertType.RELEASE, player, "", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+
+ if (!this.playerData.isBanning() && violations > 2) {
+ this.ban(player);
+ }
+ }
+
+ this.lastSlot = slot;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsI.java b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsI.java
new file mode 100644
index 0000000..83c7a3e
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsI.java
@@ -0,0 +1,45 @@
+package me.joeleoli.fairfight.check.impl.badpackets;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+import net.minecraft.server.v1_8_R3.PacketPlayInSteerVehicle;
+
+import org.bukkit.entity.Player;
+
+public class BadPacketsI extends PacketCheck {
+
+ private float lastYaw;
+ private float lastPitch;
+ private boolean ignore;
+
+ public BadPacketsI(PlayerData playerData) {
+ super(playerData, "Packets (Check 9)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInFlying) {
+ final PacketPlayInFlying flying = (PacketPlayInFlying) packet;
+
+ if (!flying.g() && flying.h()) {
+ if (this.lastYaw == flying.d() && this.lastPitch == flying.e()) {
+ if (!this.ignore) {
+ this.alert(AlertType.EXPERIMENTAL, player, "", false);
+ }
+ this.ignore = false;
+ }
+ this.lastYaw = flying.d();
+ this.lastPitch = flying.e();
+ } else {
+ this.ignore = true;
+ }
+ } else if (packet instanceof PacketPlayInSteerVehicle) {
+ this.ignore = true;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsJ.java b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsJ.java
new file mode 100644
index 0000000..8c30598
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsJ.java
@@ -0,0 +1,38 @@
+package me.joeleoli.fairfight.check.impl.badpackets;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockDig;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockPlace;
+
+import org.bukkit.entity.Player;
+
+public class BadPacketsJ extends PacketCheck {
+
+ private boolean placing;
+
+ public BadPacketsJ(PlayerData playerData) {
+ super(playerData, "Packets (Check 10)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInBlockDig) {
+ if (((PacketPlayInBlockDig) packet).c() == PacketPlayInBlockDig.EnumPlayerDigType.RELEASE_USE_ITEM) {
+ if (!this.placing && this.alert(AlertType.RELEASE, player, "", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+ if (!this.playerData.isBanning() && violations > 2) {
+ this.ban(player);
+ }
+ }
+ this.placing = false;
+ }
+ } else if (packet instanceof PacketPlayInBlockPlace) {
+ this.placing = true;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsK.java b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsK.java
new file mode 100644
index 0000000..798436c
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsK.java
@@ -0,0 +1,38 @@
+package me.joeleoli.fairfight.check.impl.badpackets;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.*;
+
+import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+
+public class BadPacketsK extends PacketCheck {
+
+ public BadPacketsK(PlayerData playerData) {
+ super(playerData, "Packets (Check 11)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInUseEntity) {
+ final PacketPlayInUseEntity useEntity = (PacketPlayInUseEntity) packet;
+ if (useEntity.a() == PacketPlayInUseEntity.EnumEntityUseAction.INTERACT_AT) {
+ final Entity targetEntity = useEntity.a(((CraftPlayer) player).getHandle().getWorld());
+ if (targetEntity instanceof EntityPlayer) {
+ final Vec3D vec3D = useEntity.b();
+ if ((Math.abs(vec3D.a) > 0.41 || Math.abs(vec3D.b) > 1.91 || Math.abs(vec3D.c) > 0.41) && this
+ .alert(AlertType.RELEASE, player, "", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+ if (!this.playerData.isBanning() && !this.playerData.isRandomBan() && violations > 2) {
+ this.randomBan(player, 100.0);
+ }
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsL.java b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsL.java
new file mode 100644
index 0000000..ad7f150
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/badpackets/BadPacketsL.java
@@ -0,0 +1,47 @@
+package me.joeleoli.fairfight.check.impl.badpackets;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.*;
+
+import org.bukkit.entity.Player;
+
+public class BadPacketsL extends PacketCheck {
+
+ private boolean sent;
+ private boolean vehicle;
+
+ public BadPacketsL(PlayerData playerData) {
+ super(playerData, "Packets (Check 12)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInFlying) {
+ if (this.sent) {
+ this.alert(AlertType.EXPERIMENTAL, player, "", false);
+ }
+
+ final boolean b = false;
+ this.vehicle = b;
+ this.sent = b;
+ } else if (packet instanceof PacketPlayInBlockPlace) {
+ final PacketPlayInBlockPlace blockPlace = (PacketPlayInBlockPlace) packet;
+
+ if (blockPlace.getFace() == 255) {
+ final ItemStack itemStack = blockPlace.getItemStack();
+
+ if (itemStack != null && itemStack.getName().toLowerCase().contains("sword") && this.playerData.isSprinting() && !this.vehicle) {
+ this.sent = true;
+ }
+ }
+ } else if (packet instanceof PacketPlayInEntityAction && ((PacketPlayInEntityAction) packet).b() == PacketPlayInEntityAction.EnumPlayerAction.STOP_SPRINTING) {
+ this.sent = false;
+ } else if (packet instanceof PacketPlayInSteerVehicle) {
+ this.vehicle = true;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/fly/FlyA.java b/src/main/java/me/joeleoli/fairfight/check/impl/fly/FlyA.java
new file mode 100644
index 0000000..4f40548
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/fly/FlyA.java
@@ -0,0 +1,58 @@
+package me.joeleoli.fairfight.check.impl.fly;
+
+import me.joeleoli.fairfight.check.checks.PositionCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.fairfight.util.update.PositionUpdate;
+
+import org.bukkit.entity.Player;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.potion.PotionEffectType;
+
+public class FlyA extends PositionCheck {
+
+ public FlyA(PlayerData playerData) {
+ super(playerData, "Flight (Check 1)");
+ }
+
+ @Override
+ public void handleCheck(final Player player, final PositionUpdate update) {
+ int vl = (int) this.getVl();
+
+ if (!this.playerData.isInLiquid() && !this.playerData.isOnGround() && this.playerData.getVelocityV() == 0) {
+ if (update.getFrom().getY() >= update.getTo().getY()) {
+ return;
+ }
+
+ final double distance = update.getTo().getY() - this.playerData.getLastGroundY();
+ double limit = 2.0;
+
+ if (player.hasPotionEffect(PotionEffectType.JUMP)) {
+ for (final PotionEffect effect : player.getActivePotionEffects()) {
+ if (effect.getType().equals(PotionEffectType.JUMP)) {
+ final int level = effect.getAmplifier() + 1;
+ limit += Math.pow(level + 4.2, 2.0) / 16.0;
+ break;
+ }
+ }
+ }
+
+ if (distance > limit) {
+ if (++vl >= 10 && this.alert(AlertType.RELEASE, player, "VL " + vl + ".", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+
+ if (!this.playerData.isBanning() && violations > 8) {
+ this.ban(player);
+ }
+ }
+ } else {
+ vl = 0;
+ }
+ } else {
+ vl = 0;
+ }
+
+ this.setVl(vl);
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/fly/FlyB.java b/src/main/java/me/joeleoli/fairfight/check/impl/fly/FlyB.java
new file mode 100644
index 0000000..ebaa0a2
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/fly/FlyB.java
@@ -0,0 +1,42 @@
+package me.joeleoli.fairfight.check.impl.fly;
+
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.fairfight.util.update.PositionUpdate;
+import org.bukkit.entity.Player;
+
+import me.joeleoli.fairfight.check.checks.PositionCheck;
+
+public class FlyB extends PositionCheck {
+
+ public FlyB(PlayerData playerData) {
+ super(playerData, "Flight (Check 2)");
+ }
+
+ @Override
+ public void handleCheck(final Player player, final PositionUpdate update) {
+ int vl = (int)this.getVl();
+
+ if (!this.playerData.isInLiquid() && !this.playerData.isOnGround()) {
+ final double offsetH = Math.hypot(update.getTo().getX() - update.getFrom().getX(), update.getTo().getZ() - update.getFrom().getZ());
+ final double offsetY = update.getTo().getY() - update.getFrom().getY();
+
+ if (offsetH > 0.0 && offsetY == 0.0) {
+ if (++vl >= 10 && this.alert(AlertType.RELEASE, player, String.format("H %.2f. VL %s.", offsetH, vl), true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+
+ if (!this.playerData.isBanning() && violations > 8) {
+ this.ban(player);
+ }
+ }
+ } else {
+ vl = 0;
+ }
+ } else {
+ vl = 0;
+ }
+
+ this.setVl(vl);
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/fly/FlyC.java b/src/main/java/me/joeleoli/fairfight/check/impl/fly/FlyC.java
new file mode 100644
index 0000000..fb25d8c
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/fly/FlyC.java
@@ -0,0 +1,103 @@
+package me.joeleoli.fairfight.check.impl.fly;
+
+import me.joeleoli.fairfight.check.checks.PositionCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.fairfight.util.update.PositionUpdate;
+
+import org.bukkit.entity.Player;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.potion.PotionEffectType;
+
+public class FlyC extends PositionCheck {
+
+ private int illegalMovements;
+ private int legalMovements;
+
+ public FlyC(PlayerData playerData) {
+ super(playerData, "Flight (Check 3)");
+ }
+
+ @Override
+ public void handleCheck(final Player player, final PositionUpdate update) {
+ if (this.playerData.getVelocityH() == 0) {
+ final double offsetH = Math.hypot(update.getTo().getX() - update.getFrom().getX(), update.getTo().getZ() - update.getFrom().getZ());
+
+ int speed = 0;
+
+ for (final PotionEffect effect : player.getActivePotionEffects()) {
+ if (effect.getType().equals(PotionEffectType.SPEED)) {
+ speed = effect.getAmplifier() + 1;
+ break;
+ }
+ }
+
+ double threshold;
+
+ if (this.playerData.isOnGround()) {
+ threshold = 0.34;
+
+ if (this.playerData.isOnStairs()) {
+ threshold = 0.45;
+ } else if (this.playerData.isOnIce() || this.playerData.getMovementsSinceIce() < 40) {
+ if (this.playerData.isUnderBlock()) {
+ threshold = 1.3;
+ } else {
+ threshold = 0.8;
+ }
+ } else if (this.playerData.isUnderBlock() || this.playerData.getMovementsSinceUnderBlock() < 40) {
+ threshold = 0.7;
+ } else if (this.playerData.isOnCarpet()) {
+ threshold = 0.7;
+ }
+
+ threshold += 0.06 * speed;
+ } else {
+ threshold = 0.36;
+
+ if (this.playerData.isOnStairs()) {
+ threshold = 0.45;
+ } else if (this.playerData.isOnIce() || this.playerData.getMovementsSinceIce() < 40) {
+ if (this.playerData.isUnderBlock()) {
+ threshold = 1.3;
+ } else {
+ threshold = 0.8;
+ }
+ } else if (this.playerData.isUnderBlock() || this.playerData.getMovementsSinceUnderBlock() < 40) {
+ threshold = 0.7;
+ } else if (this.playerData.isOnCarpet()) {
+ threshold = 0.7;
+ }
+
+ threshold += 0.02 * speed;
+ }
+
+ threshold += ((player.getWalkSpeed() > 0.2f) ? (player.getWalkSpeed() * 10.0f * 0.33f) : 0.0f);
+
+ if (offsetH > threshold) {
+ ++this.illegalMovements;
+ } else {
+ ++this.legalMovements;
+ }
+
+ final int total = this.illegalMovements + this.legalMovements;
+
+ if (total == 20) {
+ final double percentage = this.illegalMovements / 20.0 * 100.0;
+
+ if (percentage >= 45.0 && this.alert(AlertType.RELEASE, player, String.format("P %.1f.", percentage), true)) {
+ final int violations = this.playerData.getViolations(this, 30000L);
+
+ if (!this.playerData.isBanning() && violations > 5) {
+ this.ban(player);
+ }
+ }
+
+ final boolean b = false;
+ this.legalMovements = (b ? 1 : 0);
+ this.illegalMovements = (b ? 1 : 0);
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/fly/FlyD.java b/src/main/java/me/joeleoli/fairfight/check/impl/fly/FlyD.java
new file mode 100644
index 0000000..fa0f4d0
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/fly/FlyD.java
@@ -0,0 +1,27 @@
+package me.joeleoli.fairfight.check.impl.fly;
+
+import me.joeleoli.fairfight.check.checks.PositionCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.fairfight.util.update.PositionUpdate;
+import org.bukkit.entity.Player;
+
+public class FlyD extends PositionCheck {
+
+ public FlyD(PlayerData playerData) {
+ super(playerData, "Flight (Check 4)");
+ }
+
+ @Override
+ public void handleCheck(final Player player, final PositionUpdate update) {
+ final double offsetY = update.getTo().getY() - update.getFrom().getY();
+ if (this.playerData.getVelocityY() == 0.0 && this.playerData.isWasOnGround() && !this.playerData.isUnderBlock
+ () && !this.playerData.isWasUnderBlock() && !this.playerData.isInLiquid() && !this.playerData
+ .isWasInLiquid() && !this.playerData.isInWeb() && !this.playerData.isWasInWeb() && !this.playerData
+ .isOnStairs() && offsetY > 0.0 && offsetY < 0.41999998688697815 && update.getFrom().getY() % 1.0 ==
+ 0.0) {
+ this.alert(AlertType.EXPERIMENTAL, player, String.format("O %.2f.", offsetY), false);
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/inventory/InventoryA.java b/src/main/java/me/joeleoli/fairfight/check/impl/inventory/InventoryA.java
new file mode 100644
index 0000000..80688f3
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/inventory/InventoryA.java
@@ -0,0 +1,31 @@
+package me.joeleoli.fairfight.check.impl.inventory;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInWindowClick;
+
+import org.bukkit.entity.Player;
+
+public class InventoryA extends PacketCheck {
+ public InventoryA(PlayerData playerData) {
+ super(playerData, "Inventory (Check 1)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInWindowClick && ((PacketPlayInWindowClick) packet).a() == 0 && !this
+ .playerData.isInventoryOpen()) {
+ if (this.alert(AlertType.RELEASE, player, "", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+ if (!this.playerData.isBanning() && violations > 5) {
+ this.ban(player);
+ }
+ }
+ this.playerData.setInventoryOpen(true);
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/inventory/InventoryB.java b/src/main/java/me/joeleoli/fairfight/check/impl/inventory/InventoryB.java
new file mode 100644
index 0000000..e6bad95
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/inventory/InventoryB.java
@@ -0,0 +1,34 @@
+package me.joeleoli.fairfight.check.impl.inventory;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInArmAnimation;
+import net.minecraft.server.v1_8_R3.PacketPlayInEntityAction;
+
+import org.bukkit.entity.Player;
+
+public class InventoryB extends PacketCheck {
+
+ public InventoryB(PlayerData playerData) {
+ super(playerData, "Inventory (Check 2)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (((packet instanceof PacketPlayInEntityAction && ((PacketPlayInEntityAction) packet).b() == PacketPlayInEntityAction.EnumPlayerAction.START_SPRINTING) || packet instanceof PacketPlayInArmAnimation) && this.playerData.isInventoryOpen()) {
+ if (this.alert(AlertType.RELEASE, player, "", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+
+ if (!this.playerData.isBanning() && violations > 5) {
+ this.ban(player);
+ }
+ }
+
+ this.playerData.setInventoryOpen(false);
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/inventory/InventoryC.java b/src/main/java/me/joeleoli/fairfight/check/impl/inventory/InventoryC.java
new file mode 100644
index 0000000..51b7022
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/inventory/InventoryC.java
@@ -0,0 +1,68 @@
+package me.joeleoli.fairfight.check.impl.inventory;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.fairfight.util.CustomLocation;
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInWindowClick;
+import org.bukkit.entity.Player;
+
+import java.util.Deque;
+import java.util.LinkedList;
+
+public class InventoryC extends PacketCheck {
+
+ private final Deque delays;
+
+ public InventoryC(PlayerData playerData) {
+ super(playerData, "Inventory (Check 3)");
+
+ this.delays = new LinkedList<>();
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInWindowClick && System.currentTimeMillis() - this.playerData.getLastDelayedMovePacket() > 220L && !this.playerData.isAllowTeleport()) {
+ final CustomLocation lastMovePacket = this.playerData.getLastMovePacket();
+
+ if (lastMovePacket == null) {
+ return;
+ }
+
+ final long delay = System.currentTimeMillis() - lastMovePacket.getTimestamp();
+
+ this.delays.add(delay);
+
+ if (this.delays.size() == 10) {
+ double average = 0.0;
+
+ for (final long loopDelay : this.delays) {
+ average += loopDelay;
+ }
+
+ average /= this.delays.size();
+
+ this.delays.clear();
+
+ double vl = this.getVl();
+
+ if (average <= 35.0) {
+ if ((vl += 1.25) >= 4.0) {
+ if (this.alert(AlertType.RELEASE, player, String.format("AVG %.1f. VL %.2f.", average, vl), true)) {
+ if (!this.playerData.isBanning() && !this.playerData.isRandomBan() && vl >= 10.0) {
+ this.randomBan(player, 100.0);
+ }
+ } else {
+ vl = 0.0;
+ }
+ }
+ } else {
+ vl -= 0.5;
+ }
+ this.setVl(vl);
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/inventory/InventoryD.java b/src/main/java/me/joeleoli/fairfight/check/impl/inventory/InventoryD.java
new file mode 100644
index 0000000..f7d3c42
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/inventory/InventoryD.java
@@ -0,0 +1,43 @@
+package me.joeleoli.fairfight.check.impl.inventory;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInClientCommand;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+
+import org.bukkit.entity.Player;
+
+public class InventoryD extends PacketCheck {
+
+ private int stage;
+
+ public InventoryD(PlayerData playerData) {
+ super(playerData, "Inventory (Check 4)");
+ this.stage = 0;
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (this.stage == 0) {
+ if (packet instanceof PacketPlayInClientCommand && ((PacketPlayInClientCommand)packet).a() == PacketPlayInClientCommand.EnumClientCommand.OPEN_INVENTORY_ACHIEVEMENT) {
+ ++this.stage;
+ }
+ } else if (this.stage == 1) {
+ if (packet instanceof PacketPlayInFlying.PacketPlayInLook) {
+ ++this.stage;
+ } else {
+ this.stage = 0;
+ }
+ } else if (this.stage == 2) {
+ if (packet instanceof PacketPlayInFlying.PacketPlayInLook) {
+ this.alert(AlertType.EXPERIMENTAL, player, "", false);
+ }
+
+ this.stage = 0;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/inventory/InventoryE.java b/src/main/java/me/joeleoli/fairfight/check/impl/inventory/InventoryE.java
new file mode 100644
index 0000000..31bd08a
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/inventory/InventoryE.java
@@ -0,0 +1,35 @@
+package me.joeleoli.fairfight.check.impl.inventory;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInClientCommand;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+import net.minecraft.server.v1_8_R3.PacketPlayInWindowClick;
+
+import org.bukkit.entity.Player;
+
+public class InventoryE extends PacketCheck {
+
+ private boolean sent;
+
+ public InventoryE(PlayerData playerData) {
+ super(playerData, "Inventory (Check 5)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInWindowClick) {
+ if (this.sent) {
+ this.alert(AlertType.EXPERIMENTAL, player, "", true);
+ }
+ } else if (packet instanceof PacketPlayInClientCommand && ((PacketPlayInClientCommand) packet).a() == PacketPlayInClientCommand.EnumClientCommand.OPEN_INVENTORY_ACHIEVEMENT) {
+ this.sent = true;
+ } else if (packet instanceof PacketPlayInFlying) {
+ this.sent = false;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/inventory/InventoryF.java b/src/main/java/me/joeleoli/fairfight/check/impl/inventory/InventoryF.java
new file mode 100644
index 0000000..9ad342b
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/inventory/InventoryF.java
@@ -0,0 +1,35 @@
+package me.joeleoli.fairfight.check.impl.inventory;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInClientCommand;
+import net.minecraft.server.v1_8_R3.PacketPlayInCloseWindow;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+
+import org.bukkit.entity.Player;
+
+public class InventoryF extends PacketCheck {
+
+ private boolean sent;
+
+ public InventoryF(PlayerData playerData) {
+ super(playerData, "Inventory (Check 6)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInCloseWindow) {
+ if (this.sent) {
+ this.alert(AlertType.EXPERIMENTAL, player, "", true);
+ }
+ } else if (packet instanceof PacketPlayInClientCommand && ((PacketPlayInClientCommand) packet).a() == PacketPlayInClientCommand.EnumClientCommand.OPEN_INVENTORY_ACHIEVEMENT) {
+ this.sent = true;
+ } else if (packet instanceof PacketPlayInFlying) {
+ this.sent = false;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/inventory/InventoryG.java b/src/main/java/me/joeleoli/fairfight/check/impl/inventory/InventoryG.java
new file mode 100644
index 0000000..5e0e678
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/inventory/InventoryG.java
@@ -0,0 +1,40 @@
+package me.joeleoli.fairfight.check.impl.inventory;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import net.minecraft.server.v1_8_R3.*;
+import org.bukkit.entity.Player;
+
+public class InventoryG extends PacketCheck {
+
+ private boolean sent;
+ private boolean vehicle;
+
+ public InventoryG(PlayerData playerData) {
+ super(playerData, "Inventory (Check 7)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInFlying) {
+ if (this.sent) {
+ this.alert(AlertType.EXPERIMENTAL, player, "", true);
+ }
+ final boolean b = false;
+ this.vehicle = b;
+ this.sent = b;
+ } else if (packet instanceof PacketPlayInClientCommand && ((PacketPlayInClientCommand) packet).a() ==
+ PacketPlayInClientCommand.EnumClientCommand.OPEN_INVENTORY_ACHIEVEMENT) {
+ if (this.playerData.isSprinting() && !this.vehicle) {
+ this.sent = true;
+ }
+ } else if (packet instanceof PacketPlayInEntityAction && ((PacketPlayInEntityAction) packet).b() ==
+ PacketPlayInEntityAction.EnumPlayerAction.STOP_SPRINTING) {
+ this.sent = false;
+ } else if (packet instanceof PacketPlayInSteerVehicle) {
+ this.vehicle = true;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraA.java b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraA.java
new file mode 100644
index 0000000..cf65540
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraA.java
@@ -0,0 +1,41 @@
+package me.joeleoli.fairfight.check.impl.killaura;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInArmAnimation;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+import net.minecraft.server.v1_8_R3.PacketPlayInUseEntity;
+
+import org.bukkit.entity.Player;
+
+public class KillAuraA extends PacketCheck {
+ private boolean sent;
+
+ public KillAuraA(PlayerData playerData) {
+ super(playerData, "Kill-Aura (Check 1)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInUseEntity && ((PacketPlayInUseEntity) packet).a() == PacketPlayInUseEntity
+ .EnumEntityUseAction.ATTACK) {
+ if (!this.sent) {
+ if (this.alert(AlertType.RELEASE, player, "", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+ if (!this.playerData.isBanning() && violations > 5) {
+ this.ban(player);
+ }
+ }
+ } else {
+ this.sent = false;
+ }
+ } else if (packet instanceof PacketPlayInArmAnimation) {
+ this.sent = true;
+ } else if (packet instanceof PacketPlayInFlying) {
+ this.sent = false;
+ }
+ }
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraB.java b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraB.java
new file mode 100644
index 0000000..ee6f9db
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraB.java
@@ -0,0 +1,52 @@
+package me.joeleoli.fairfight.check.impl.killaura;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInArmAnimation;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockDig;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+import org.bukkit.entity.Player;
+
+public class KillAuraB extends PacketCheck {
+ private boolean sent;
+ private boolean failed;
+ private int movements;
+
+ public KillAuraB(PlayerData playerData) {
+ super(playerData, "Kill-Aura (Check 2)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (this.playerData.isDigging() && !this.playerData.isInstantBreakDigging() &&
+ System.currentTimeMillis() - this.playerData.getLastDelayedMovePacket() > 220L &&
+ this.playerData.getLastMovePacket() != null &&
+ System.currentTimeMillis() - this.playerData.getLastMovePacket().getTimestamp() < 110L) {
+ int vl = (int) this.getVl();
+ if (packet instanceof PacketPlayInBlockDig &&
+ ((PacketPlayInBlockDig) packet).c() == PacketPlayInBlockDig.EnumPlayerDigType.START_DESTROY_BLOCK) {
+ this.movements = 0;
+ vl = 0;
+ } else if (packet instanceof PacketPlayInArmAnimation && this.movements >= 2) {
+ if (this.sent) {
+ if (!this.failed) {
+ if (++vl >= 5) {
+ this.alert(AlertType.EXPERIMENTAL, player, "VL " + vl + ".", false);
+ }
+ this.failed = true;
+ }
+ } else {
+ this.sent = true;
+ }
+ } else if (packet instanceof PacketPlayInFlying) {
+ final boolean b = false;
+ this.failed = b;
+ this.sent = b;
+ ++this.movements;
+ }
+ this.setVl(vl);
+ }
+ }
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraC.java b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraC.java
new file mode 100644
index 0000000..4b306d5
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraC.java
@@ -0,0 +1,68 @@
+package me.joeleoli.fairfight.check.impl.killaura;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.fairfight.util.CustomLocation;
+import me.joeleoli.fairfight.util.MathUtil;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+
+import org.bukkit.entity.Player;
+
+public class KillAuraC extends PacketCheck {
+
+ private float lastYaw;
+
+ public KillAuraC(PlayerData playerData) {
+ super(playerData, "Kill-Aura (Check 3)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (this.playerData.getLastTarget() == null) {
+ return;
+ }
+
+ if (packet instanceof PacketPlayInFlying) {
+ final PacketPlayInFlying flying = (PacketPlayInFlying) packet;
+
+ if (flying.h() && !this.playerData.isAllowTeleport()) {
+ final CustomLocation targetLocation = this.playerData.getLastPlayerPacket(this.playerData.getLastTarget(), MathUtil.pingFormula(this.playerData.getPing()));
+
+ if (targetLocation == null) {
+ return;
+ }
+
+ final CustomLocation playerLocation = this.playerData.getLastMovePacket();
+
+ if (playerLocation.getX() == targetLocation.getX()) {
+ return;
+ }
+
+ if (targetLocation.getZ() == playerLocation.getZ()) {
+ return;
+ }
+
+ final float yaw = flying.d();
+
+ if (yaw != this.lastYaw) {
+ final float bodyYaw = MathUtil.getDistanceBetweenAngles(yaw, MathUtil.getRotationFromPosition
+ (playerLocation, targetLocation)[0]);
+
+ if (bodyYaw == 0.0f && this.alert(AlertType.RELEASE, player, null, true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+
+ if (!this.playerData.isBanning() && violations > 5) {
+ this.ban(player);
+ }
+ }
+ }
+
+ this.lastYaw = yaw;
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraD.java b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraD.java
new file mode 100644
index 0000000..6276324
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraD.java
@@ -0,0 +1,30 @@
+package me.joeleoli.fairfight.check.impl.killaura;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInUseEntity;
+
+import org.bukkit.entity.Player;
+
+public class KillAuraD extends PacketCheck {
+
+ public KillAuraD(PlayerData playerData) {
+ super(playerData, "Kill-Aura (Check 4)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInUseEntity && ((PacketPlayInUseEntity) packet).a() == PacketPlayInUseEntity
+ .EnumEntityUseAction.ATTACK && this.playerData.isPlacing() && this.alert(AlertType.RELEASE, player,
+ "", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+ if (!this.playerData.isBanning() && violations > 2) {
+ this.ban(player);
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraE.java b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraE.java
new file mode 100644
index 0000000..2ef28dd
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraE.java
@@ -0,0 +1,59 @@
+package me.joeleoli.fairfight.check.impl.killaura;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.fairfight.util.CustomLocation;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+import net.minecraft.server.v1_8_R3.PacketPlayInUseEntity;
+
+import org.bukkit.entity.Player;
+
+public class KillAuraE extends PacketCheck {
+
+ private long lastAttack;
+ private boolean attack;
+
+ public KillAuraE(PlayerData playerData) {
+ super(playerData, "Kill-Aura (Check 5)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ double vl = this.getVl();
+
+ if (packet instanceof PacketPlayInUseEntity && ((PacketPlayInUseEntity)packet).a() == PacketPlayInUseEntity.EnumEntityUseAction.ATTACK && System.currentTimeMillis() - this.playerData.getLastDelayedMovePacket() > 220L && !this.playerData.isAllowTeleport()) {
+ final CustomLocation lastMovePacket = this.playerData.getLastMovePacket();
+
+ if (lastMovePacket == null) {
+ return;
+ }
+
+ final long delay = System.currentTimeMillis() - lastMovePacket.getTimestamp();
+
+ if (delay <= 25.0) {
+ this.lastAttack = System.currentTimeMillis();
+ this.attack = true;
+ } else {
+ vl -= 0.25;
+ }
+ } else if (packet instanceof PacketPlayInFlying && this.attack) {
+ final long time = System.currentTimeMillis() - this.lastAttack;
+
+ if (time >= 25L) {
+ if (++vl >= 10.0 && this.alert(AlertType.RELEASE, player, String.format("T %s. VL %.2f.", time, vl), false) && !this.playerData.isBanning() && vl >= 20.0) {
+ this.ban(player);
+ }
+ } else {
+ vl -= 0.25;
+ }
+
+ this.attack = false;
+ }
+
+ this.setVl(vl);
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraF.java b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraF.java
new file mode 100644
index 0000000..03d2c49
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraF.java
@@ -0,0 +1,43 @@
+package me.joeleoli.fairfight.check.impl.killaura;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockDig;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+import net.minecraft.server.v1_8_R3.PacketPlayInUseEntity;
+
+import org.bukkit.entity.Player;
+
+public class KillAuraF extends PacketCheck {
+
+ private boolean sent;
+
+ public KillAuraF(PlayerData playerData) {
+ super(playerData, "Kill-Aura (Check 6)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInUseEntity) {
+ if (this.sent && this.alert(AlertType.RELEASE, player, "", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+
+ if (!this.playerData.isBanning() && violations > 2) {
+ this.ban(player);
+ }
+ }
+ } else if (packet instanceof PacketPlayInBlockDig) {
+ final PacketPlayInBlockDig.EnumPlayerDigType digType = ((PacketPlayInBlockDig) packet).c();
+
+ if (digType == PacketPlayInBlockDig.EnumPlayerDigType.START_DESTROY_BLOCK || digType == PacketPlayInBlockDig.EnumPlayerDigType.ABORT_DESTROY_BLOCK || digType == PacketPlayInBlockDig.EnumPlayerDigType.RELEASE_USE_ITEM) {
+ this.sent = true;
+ }
+ } else if (packet instanceof PacketPlayInFlying) {
+ this.sent = false;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraG.java b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraG.java
new file mode 100644
index 0000000..67e2bb2
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraG.java
@@ -0,0 +1,75 @@
+package me.joeleoli.fairfight.check.impl.killaura;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import net.minecraft.server.v1_8_R3.*;
+import org.bukkit.entity.Player;
+
+public class KillAuraG extends PacketCheck {
+
+ private int stage;
+
+ public KillAuraG(PlayerData playerData) {
+ super(playerData, "Kill-Aura (Check 7)");
+ this.stage = 0;
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ final int calculusStage = this.stage % 6;
+ if (calculusStage == 0) {
+ if (packet instanceof PacketPlayInArmAnimation) {
+ ++this.stage;
+ }
+ else {
+ this.stage = 0;
+ }
+ }
+ else if (calculusStage == 1) {
+ if (packet instanceof PacketPlayInUseEntity) {
+ ++this.stage;
+ }
+ else {
+ this.stage = 0;
+ }
+ }
+ else if (calculusStage == 2) {
+ if (packet instanceof PacketPlayInEntityAction) {
+ ++this.stage;
+ }
+ else {
+ this.stage = 0;
+ }
+ }
+ else if (calculusStage == 3) {
+ if (packet instanceof PacketPlayInFlying) {
+ ++this.stage;
+ }
+ else {
+ this.stage = 0;
+ }
+ }
+ else if (calculusStage == 4) {
+ if (packet instanceof PacketPlayInEntityAction) {
+ ++this.stage;
+ }
+ else {
+ this.stage = 0;
+ }
+ }
+ else if (calculusStage == 5) {
+ if (packet instanceof PacketPlayInFlying) {
+ if (++this.stage >= 30 && this.alert(AlertType.RELEASE, player, "S " + this.stage + ".", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+ if (!this.playerData.isBanning() && violations > 5) {
+ this.ban(player);
+ }
+ }
+ }
+ else {
+ this.stage = 0;
+ }
+ }
+ }
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraH.java b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraH.java
new file mode 100644
index 0000000..f70a97c
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraH.java
@@ -0,0 +1,43 @@
+package me.joeleoli.fairfight.check.impl.killaura;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockDig;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+import net.minecraft.server.v1_8_R3.PacketPlayInUseEntity;
+
+import org.bukkit.entity.Player;
+
+public class KillAuraH extends PacketCheck {
+
+ private boolean sent;
+
+ public KillAuraH(PlayerData playerData) {
+ super(playerData, "Kill-Aura (Check 8)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInBlockDig) {
+ final PacketPlayInBlockDig.EnumPlayerDigType digType = ((PacketPlayInBlockDig) packet).c();
+
+ if ((digType == PacketPlayInBlockDig.EnumPlayerDigType.START_DESTROY_BLOCK || digType ==
+ PacketPlayInBlockDig.EnumPlayerDigType.RELEASE_USE_ITEM) && this.sent && this.alert(AlertType
+ .RELEASE, player, "", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+
+ if (!this.playerData.isBanning() && violations > 2) {
+ this.ban(player);
+ }
+ }
+ } else if (packet instanceof PacketPlayInUseEntity) {
+ this.sent = true;
+ } else if (packet instanceof PacketPlayInFlying) {
+ this.sent = false;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraI.java b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraI.java
new file mode 100644
index 0000000..3b01d5e
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraI.java
@@ -0,0 +1,35 @@
+package me.joeleoli.fairfight.check.impl.killaura;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInArmAnimation;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockDig;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+
+import org.bukkit.entity.Player;
+
+public class KillAuraI extends PacketCheck {
+
+ private boolean sent;
+
+ public KillAuraI(PlayerData playerData) {
+ super(playerData, "Kill-Aura (Check 9)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInBlockDig && ((PacketPlayInBlockDig) packet).c() == PacketPlayInBlockDig.EnumPlayerDigType.STOP_DESTROY_BLOCK) {
+ if (this.sent) {
+ this.alert(AlertType.EXPERIMENTAL, player, "", false);
+ }
+ } else if (packet instanceof PacketPlayInArmAnimation) {
+ this.sent = true;
+ } else if (packet instanceof PacketPlayInFlying) {
+ this.sent = false;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraJ.java b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraJ.java
new file mode 100644
index 0000000..9e8498f
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraJ.java
@@ -0,0 +1,36 @@
+package me.joeleoli.fairfight.check.impl.killaura;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+import net.minecraft.server.v1_8_R3.PacketPlayInHeldItemSlot;
+import net.minecraft.server.v1_8_R3.PacketPlayInUseEntity;
+
+import org.bukkit.entity.Player;
+
+public class KillAuraJ extends PacketCheck {
+
+ private boolean sent;
+
+ public KillAuraJ(PlayerData playerData) {
+ super(playerData, "Kill-Aura (Check 10)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInHeldItemSlot) {
+ if (this.sent) {
+ this.alert(AlertType.EXPERIMENTAL, player, "", false);
+ }
+ } else if (packet instanceof PacketPlayInUseEntity && ((PacketPlayInUseEntity) packet).a() ==
+ PacketPlayInUseEntity.EnumEntityUseAction.ATTACK) {
+ this.sent = true;
+ } else if (packet instanceof PacketPlayInFlying) {
+ this.sent = false;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraK.java b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraK.java
new file mode 100644
index 0000000..25bcc0a
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraK.java
@@ -0,0 +1,63 @@
+package me.joeleoli.fairfight.check.impl.killaura;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInArmAnimation;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+import net.minecraft.server.v1_8_R3.PacketPlayInUseEntity;
+
+import org.bukkit.entity.Player;
+
+public class KillAuraK extends PacketCheck {
+
+ private int ticksSinceStage;
+ private int streak;
+ private int stage;
+
+ public KillAuraK(PlayerData playerData) {
+ super(playerData, "Kill-Aura (Check 11)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInArmAnimation) {
+ if (this.stage == 0) {
+ this.stage = 1;
+ } else {
+ final boolean b = false;
+ this.stage = (b ? 1 : 0);
+ this.streak = (b ? 1 : 0);
+ }
+ } else if (packet instanceof PacketPlayInUseEntity) {
+ if (this.stage == 1) {
+ ++this.stage;
+ } else {
+ this.stage = 0;
+ }
+ } else if (packet instanceof PacketPlayInFlying.PacketPlayInPositionLook) {
+ if (this.stage == 2) {
+ ++this.stage;
+ } else {
+ this.stage = 0;
+ }
+ } else if (packet instanceof PacketPlayInFlying.PacketPlayInPosition) {
+ if (this.stage == 3) {
+ if (++this.streak >= 15) {
+ this.alert(AlertType.EXPERIMENTAL, player, "STR " + this.streak + ".", false);
+ }
+
+ this.ticksSinceStage = 0;
+ }
+
+ this.stage = 0;
+ }
+
+ if (packet instanceof PacketPlayInFlying && ++this.ticksSinceStage > 40) {
+ this.streak = 0;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraL.java b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraL.java
new file mode 100644
index 0000000..df65547
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraL.java
@@ -0,0 +1,43 @@
+package me.joeleoli.fairfight.check.impl.killaura;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInEntityAction;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+import net.minecraft.server.v1_8_R3.PacketPlayInUseEntity;
+
+import org.bukkit.entity.Player;
+
+public class KillAuraL extends PacketCheck {
+
+ private boolean sent;
+
+ public KillAuraL(PlayerData playerData) {
+ super(playerData, "Kill-Aura (Check 12)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInUseEntity && ((PacketPlayInUseEntity) packet).a() == PacketPlayInUseEntity.EnumEntityUseAction.ATTACK) {
+ if (this.sent && this.alert(AlertType.RELEASE, player, "", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+
+ if (!this.playerData.isBanning() && violations > 2) {
+ this.ban(player);
+ }
+ }
+ } else if (packet instanceof PacketPlayInEntityAction) {
+ final PacketPlayInEntityAction.EnumPlayerAction action = ((PacketPlayInEntityAction) packet).b();
+
+ if (action == PacketPlayInEntityAction.EnumPlayerAction.START_SPRINTING || action == PacketPlayInEntityAction.EnumPlayerAction.STOP_SPRINTING || action == PacketPlayInEntityAction.EnumPlayerAction.START_SNEAKING || action == PacketPlayInEntityAction.EnumPlayerAction.STOP_SNEAKING) {
+ this.sent = true;
+ }
+ } else if (packet instanceof PacketPlayInFlying) {
+ this.sent = false;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraM.java b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraM.java
new file mode 100644
index 0000000..45958a6
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraM.java
@@ -0,0 +1,47 @@
+package me.joeleoli.fairfight.check.impl.killaura;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInArmAnimation;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+import net.minecraft.server.v1_8_R3.PacketPlayInUseEntity;
+
+import org.bukkit.entity.Player;
+
+public class KillAuraM extends PacketCheck {
+
+ private int swings;
+ private int attacks;
+
+ public KillAuraM(PlayerData playerData) {
+ super(playerData, "Kill-Aura (Check 13)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (!this.playerData.isDigging() && !this.playerData.isPlacing()) {
+ if (packet instanceof PacketPlayInFlying) {
+ if (this.attacks > 0 && this.swings > this.attacks) {
+ this.alert(AlertType.EXPERIMENTAL, player, "S " + this.swings + ". A " + this.attacks + ".", false);
+ }
+
+ final KillAuraN auraN = this.playerData.getCheck(KillAuraN.class);
+
+ if (auraN != null) {
+ auraN.handleCheck(player, new int[]{this.swings, this.attacks});
+ }
+
+ this.swings = 0;
+ this.attacks = 0;
+ } else if (packet instanceof PacketPlayInArmAnimation) {
+ ++this.swings;
+ } else if (packet instanceof PacketPlayInUseEntity && ((PacketPlayInUseEntity) packet).a() == PacketPlayInUseEntity.EnumEntityUseAction.ATTACK) {
+ ++this.attacks;
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraN.java b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraN.java
new file mode 100644
index 0000000..fbfc966
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraN.java
@@ -0,0 +1,50 @@
+package me.joeleoli.fairfight.check.impl.killaura;
+
+import me.joeleoli.fairfight.check.AbstractCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import org.bukkit.entity.Player;
+
+public class KillAuraN extends AbstractCheck {
+
+ private int doubleSwings;
+ private int doubleAttacks;
+ private int bareSwings;
+
+ public KillAuraN(PlayerData playerData) {
+ super(playerData, int[].class, "Kill-Aura (Check 14)");
+ }
+
+ @Override
+ public void handleCheck(final Player player, final int[] ints) {
+ final int swings = ints[0];
+ final int attacks = ints[1];
+
+ if (swings > 1 && attacks == 0) {
+ ++this.doubleSwings;
+ } else if (swings == 1 && attacks == 0) {
+ ++this.bareSwings;
+ } else if (attacks > 1) {
+ ++this.doubleAttacks;
+ }
+
+ if (this.doubleSwings + this.doubleAttacks == 20) {
+ double vl = this.getVl();
+
+ if (this.doubleSwings == 0) {
+ if (this.bareSwings > 10 && ++vl > 3.0) {
+ this.alert(AlertType.EXPERIMENTAL, player, "BS " + this.bareSwings + ", VL " + vl, false);
+ }
+ } else {
+ --vl;
+ }
+
+ this.setVl(vl);
+ this.doubleSwings = 0;
+ this.doubleAttacks = 0;
+ this.bareSwings = 0;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraO.java b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraO.java
new file mode 100644
index 0000000..b6d8458
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraO.java
@@ -0,0 +1,38 @@
+package me.joeleoli.fairfight.check.impl.killaura;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInCloseWindow;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+import net.minecraft.server.v1_8_R3.PacketPlayInUseEntity;
+
+import org.bukkit.entity.Player;
+
+public class KillAuraO extends PacketCheck {
+
+ private boolean sent;
+
+ public KillAuraO(PlayerData playerData) {
+ super(playerData, "Kill-Aura (Check 15)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInUseEntity && ((PacketPlayInUseEntity)packet).a() == PacketPlayInUseEntity.EnumEntityUseAction.ATTACK) {
+ if (this.sent && this.alert(AlertType.RELEASE, player, "", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+
+ if (!this.playerData.isBanning() && violations > 2) {
+ this.ban(player);
+ }
+ }
+ } else if (packet instanceof PacketPlayInCloseWindow) {
+ this.sent = true;
+ } else if (packet instanceof PacketPlayInFlying) {
+ this.sent = false;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraP.java b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraP.java
new file mode 100644
index 0000000..f9df31d
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraP.java
@@ -0,0 +1,40 @@
+package me.joeleoli.fairfight.check.impl.killaura;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInClientCommand;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+import net.minecraft.server.v1_8_R3.PacketPlayInUseEntity;
+
+import org.bukkit.entity.Player;
+
+public class KillAuraP extends PacketCheck {
+
+ private boolean sent;
+
+ public KillAuraP(PlayerData playerData) {
+ super(playerData, "Kill-Aura (Check 16)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInClientCommand && ((PacketPlayInClientCommand) packet).a() == PacketPlayInClientCommand.EnumClientCommand.OPEN_INVENTORY_ACHIEVEMENT) {
+ if (this.sent && this.alert(AlertType.RELEASE, player, "", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+
+ if (!this.playerData.isBanning() && violations > 2) {
+ this.ban(player);
+ }
+ }
+ } else if (packet instanceof PacketPlayInUseEntity && ((PacketPlayInUseEntity) packet).a() ==
+ PacketPlayInUseEntity.EnumEntityUseAction.ATTACK) {
+ this.sent = true;
+ } else if (packet instanceof PacketPlayInFlying) {
+ this.sent = false;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraQ.java b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraQ.java
new file mode 100644
index 0000000..4d00dc3
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraQ.java
@@ -0,0 +1,48 @@
+package me.joeleoli.fairfight.check.impl.killaura;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockPlace;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+import net.minecraft.server.v1_8_R3.PacketPlayInUseEntity;
+
+import org.bukkit.entity.Player;
+
+public class KillAuraQ extends PacketCheck {
+
+ private boolean sentAttack;
+ private boolean sentInteract;
+
+ public KillAuraQ(PlayerData playerData) {
+ super(playerData, "Kill-Aura (Check 17)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInBlockPlace) {
+ if (this.sentAttack && !this.sentInteract && this.alert(AlertType.RELEASE, player, "", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+
+ if (!this.playerData.isBanning() && violations > 2) {
+ this.ban(player);
+ }
+ }
+ } else if (packet instanceof PacketPlayInUseEntity) {
+ final PacketPlayInUseEntity.EnumEntityUseAction action = ((PacketPlayInUseEntity) packet).a();
+
+ if (action == PacketPlayInUseEntity.EnumEntityUseAction.ATTACK) {
+ this.sentAttack = true;
+ } else if (action == PacketPlayInUseEntity.EnumEntityUseAction.INTERACT) {
+ this.sentInteract = true;
+ }
+ } else if (packet instanceof PacketPlayInFlying) {
+ final boolean b = false;
+ this.sentInteract = b;
+ this.sentAttack = b;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraR.java b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraR.java
new file mode 100644
index 0000000..24dc46d
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraR.java
@@ -0,0 +1,39 @@
+package me.joeleoli.fairfight.check.impl.killaura;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockPlace;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+import net.minecraft.server.v1_8_R3.PacketPlayInUseEntity;
+
+import org.bukkit.entity.Player;
+
+public class KillAuraR extends PacketCheck {
+
+ private boolean sentUseEntity;
+
+ public KillAuraR(PlayerData playerData) {
+ super(playerData, "Kill-Aura (Check 18)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInBlockPlace) {
+ if (((PacketPlayInBlockPlace) packet).getFace() != 255 && this.sentUseEntity && this.alert(AlertType.RELEASE, player, "", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+
+ if (!this.playerData.isBanning() && violations > 2) {
+ this.ban(player);
+ }
+ }
+ } else if (packet instanceof PacketPlayInUseEntity) {
+ this.sentUseEntity = true;
+ } else if (packet instanceof PacketPlayInFlying) {
+ this.sentUseEntity = false;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraS.java b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraS.java
new file mode 100644
index 0000000..bd3ba28
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraS.java
@@ -0,0 +1,51 @@
+package me.joeleoli.fairfight.check.impl.killaura;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.*;
+
+import org.bukkit.entity.Player;
+
+public class KillAuraS extends PacketCheck {
+
+ private boolean sentArmAnimation;
+ private boolean sentAttack;
+ private boolean sentBlockPlace;
+ private boolean sentUseEntity;
+
+ public KillAuraS(PlayerData playerData) {
+ super(playerData, "Kill-Aura (Check 19)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInArmAnimation) {
+ this.sentArmAnimation = true;
+ } else if (packet instanceof PacketPlayInUseEntity) {
+ if (((PacketPlayInUseEntity)packet).a() == PacketPlayInUseEntity.EnumEntityUseAction.ATTACK) {
+ this.sentAttack = true;
+ } else {
+ this.sentUseEntity = true;
+ }
+ } else if (packet instanceof PacketPlayInBlockPlace && ((PacketPlayInBlockPlace)packet).getItemStack() != null && ((PacketPlayInBlockPlace)packet).getItemStack().getName().toLowerCase().contains("sword")) {
+ this.sentBlockPlace = true;
+ } else if (packet instanceof PacketPlayInFlying) {
+ if (this.sentArmAnimation && !this.sentAttack && this.sentBlockPlace && this.sentUseEntity && this.alert(AlertType.RELEASE, player, "", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+
+ if (!this.playerData.isBanning() && violations > 2) {
+ this.ban(player);
+ }
+ }
+
+ final boolean b = false;
+ this.sentUseEntity = b;
+ this.sentBlockPlace = b;
+ this.sentAttack = b;
+ this.sentArmAnimation = b;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraT.java b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraT.java
new file mode 100644
index 0000000..12e5a14
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/killaura/KillAuraT.java
@@ -0,0 +1,31 @@
+package me.joeleoli.fairfight.check.impl.killaura;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+import net.minecraft.server.v1_8_R3.PacketPlayInUseEntity;
+
+import org.bukkit.entity.Player;
+
+public class KillAuraT extends PacketCheck {
+
+ private boolean sent;
+
+ public KillAuraT(PlayerData playerData) {
+ super(playerData, "Kill-Aura (Check 20)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInUseEntity) {
+ if (!this.sent) {
+ this.sent = true;
+ }
+ } else if (packet instanceof PacketPlayInFlying) {
+ this.sent = false;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/range/RangeA.java b/src/main/java/me/joeleoli/fairfight/check/impl/range/RangeA.java
new file mode 100644
index 0000000..ebf7b04
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/range/RangeA.java
@@ -0,0 +1,103 @@
+package me.joeleoli.fairfight.check.impl.range;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.fairfight.util.MathUtil;
+
+import net.minecraft.server.v1_8_R3.Entity;
+import net.minecraft.server.v1_8_R3.EntityPlayer;
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+import net.minecraft.server.v1_8_R3.PacketPlayInUseEntity;
+
+import org.bukkit.GameMode;
+import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+
+import me.joeleoli.fairfight.util.CustomLocation;
+
+public class RangeA extends PacketCheck {
+
+ private boolean sameTick;
+
+ public RangeA(PlayerData playerData) {
+ super(playerData, "Range");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInUseEntity && !player.getGameMode().equals(GameMode.CREATIVE) &&
+ System.currentTimeMillis() - this.playerData.getLastDelayedMovePacket() > 220L &&
+ this.playerData.getLastMovePacket() != null &&
+ System.currentTimeMillis() - this.playerData.getLastMovePacket().getTimestamp() < 110L && !this.sameTick) {
+
+ PacketPlayInUseEntity useEntity = (PacketPlayInUseEntity) packet;
+
+ if (useEntity.a() == PacketPlayInUseEntity.EnumEntityUseAction.ATTACK) {
+ final Entity targetEntity = useEntity.a(((CraftPlayer) player).getHandle().getWorld());
+
+ if (targetEntity instanceof EntityPlayer) {
+ final Player target = (Player) targetEntity.getBukkitEntity();
+ final CustomLocation targetLocation = this.playerData.getLastPlayerPacket(target.getUniqueId(), MathUtil.pingFormula(this.playerData.getPing()));
+
+ if (targetLocation == null) {
+ return;
+ }
+
+ long diff = System.currentTimeMillis() - targetLocation.getTimestamp();
+ long estimate = MathUtil.pingFormula(this.playerData.getPing()) * 50L;
+ long diffEstimate = diff - estimate;
+
+ if (diffEstimate >= 500L) {
+ return;
+ }
+
+ CustomLocation playerLocation = this.playerData.getLastMovePacket();
+ PlayerData targetData = this.getPlugin().getPlayerDataManager().getPlayerData(target);
+
+ if (targetData == null) {
+ return;
+ }
+
+ double range = Math.hypot(playerLocation.getX() - targetLocation.getX(), playerLocation.getZ() - targetLocation.getZ());
+
+ if (range > 6.5) {
+ return;
+ }
+
+ double threshold = 3.3;
+
+ if (!targetData.isSprinting() ||
+ MathUtil.getDistanceBetweenAngles(playerLocation.getYaw(), targetLocation.getYaw()) <= 90.0) {
+ threshold = 4.0;
+ }
+
+ double vl = this.getVl();
+
+ if (range > threshold) {
+ if (++vl >= 12.5) {
+ boolean ex = this.getPlugin().getRangeVl() == 0.0;
+
+ if (this.alert(ex ? AlertType.EXPERIMENTAL : AlertType.RELEASE, player, String.format("P %.1f. R %.3f. T %.2f. D %s. VL %.2f.", range - threshold + 3.0, range, threshold, diffEstimate, vl), false)) {
+ if (!this.playerData.isBanning() && vl >= this.getPlugin().getRangeVl() && !ex) {
+ this.ban(player);
+ }
+ } else {
+ vl = 0.0;
+ }
+ }
+ } else if (range >= 2.0) {
+ vl -= 0.25;
+ }
+
+ this.setVl(vl);
+ this.sameTick = true;
+ }
+ }
+ } else if (packet instanceof PacketPlayInFlying) {
+ this.sameTick = false;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/scaffold/ScaffoldA.java b/src/main/java/me/joeleoli/fairfight/check/impl/scaffold/ScaffoldA.java
new file mode 100644
index 0000000..003e99a
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/scaffold/ScaffoldA.java
@@ -0,0 +1,63 @@
+package me.joeleoli.fairfight.check.impl.scaffold;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.fairfight.util.CustomLocation;
+
+import net.minecraft.server.v1_8_R3.BlockPosition;
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockPlace;
+
+import org.bukkit.entity.Player;
+
+public class ScaffoldA extends PacketCheck {
+
+ private BlockPosition lastBlock;
+ private float lastYaw;
+ private float lastPitch;
+ private float lastX;
+ private float lastY;
+ private float lastZ;
+
+ public ScaffoldA(PlayerData playerData) {
+ super(playerData, "Placement (Check 1)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInBlockPlace) {
+ final PacketPlayInBlockPlace blockPlace = (PacketPlayInBlockPlace) packet;
+ final BlockPosition blockPosition = blockPlace.a();
+ final float x = blockPlace.d();
+ final float y = blockPlace.e();
+ final float z = blockPlace.f();
+
+ if (this.lastBlock != null && (blockPosition.getX() != this.lastBlock.getX() || blockPosition.getY() != this.lastBlock.getY() || blockPosition.getZ() != this.lastBlock.getZ())) {
+ final CustomLocation location = this.playerData.getLastMovePacket();
+ double vl = this.getVl();
+
+ if (this.lastX == x && this.lastY == y && this.lastZ == z) {
+ final float deltaAngle = Math.abs(this.lastYaw - location.getYaw()) + Math.abs(this.lastPitch - location.getPitch());
+
+ if (deltaAngle > 4.0f && ++vl >= 4.0) {
+ this.alert(AlertType.EXPERIMENTAL, player, String.format("X %.1f, Y %.1f, Z %.1f, DA %.1f, VL %.1f", x, y, z, deltaAngle, vl), false);
+ }
+ } else {
+ vl -= 0.5;
+ }
+
+ this.setVl(vl);
+
+ this.lastX = x;
+ this.lastY = y;
+ this.lastZ = z;
+ this.lastYaw = location.getYaw();
+ this.lastPitch = location.getPitch();
+ }
+
+ this.lastBlock = blockPosition;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/scaffold/ScaffoldB.java b/src/main/java/me/joeleoli/fairfight/check/impl/scaffold/ScaffoldB.java
new file mode 100644
index 0000000..bf0466a
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/scaffold/ScaffoldB.java
@@ -0,0 +1,51 @@
+package me.joeleoli.fairfight.check.impl.scaffold;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.fairfight.util.CustomLocation;
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockPlace;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+import org.bukkit.entity.Player;
+
+public class ScaffoldB extends PacketCheck {
+
+ private long lastPlace;
+ private boolean place;
+
+ public ScaffoldB(PlayerData playerData) {
+ super(playerData, "Placement (Check 2)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ double vl = this.getVl();
+ if (packet instanceof PacketPlayInBlockPlace && System.currentTimeMillis() - this.playerData
+ .getLastDelayedMovePacket() > 220L && !this.playerData.isAllowTeleport()) {
+ final CustomLocation lastMovePacket = this.playerData.getLastMovePacket();
+ if (lastMovePacket == null) {
+ return;
+ }
+ final long delay = System.currentTimeMillis() - lastMovePacket.getTimestamp();
+ if (delay <= 25.0) {
+ this.lastPlace = System.currentTimeMillis();
+ this.place = true;
+ } else {
+ vl -= 0.25;
+ }
+ } else if (packet instanceof PacketPlayInFlying && this.place) {
+ final long time = System.currentTimeMillis() - this.lastPlace;
+ if (time >= 25L) {
+ if (++vl >= 10.0) {
+ this.alert(AlertType.EXPERIMENTAL, player, String.format("T %s. VL %.2f.", time, vl), false);
+ }
+ } else {
+ vl -= 0.25;
+ }
+ this.place = false;
+ }
+ this.setVl(vl);
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/scaffold/ScaffoldC.java b/src/main/java/me/joeleoli/fairfight/check/impl/scaffold/ScaffoldC.java
new file mode 100644
index 0000000..d59a8d7
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/scaffold/ScaffoldC.java
@@ -0,0 +1,75 @@
+package me.joeleoli.fairfight.check.impl.scaffold;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInArmAnimation;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockPlace;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+
+import org.bukkit.entity.Player;
+
+public class ScaffoldC extends PacketCheck {
+
+ private int looks;
+ private int stage;
+
+ public ScaffoldC(PlayerData playerData) {
+ super(playerData, "Placement (Check 3)");
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ double vl = this.getVl();
+
+ if (packet instanceof PacketPlayInFlying.PacketPlayInLook) {
+ if (this.stage == 0) {
+ ++this.stage;
+ } else if (this.stage == 4) {
+ if ((vl += 1.75) > 3.5) {
+ this.alert(AlertType.EXPERIMENTAL, player, String.format("VL %.2f.", vl), false);
+ }
+
+ this.stage = 0;
+ } else {
+ final boolean b = false;
+ this.looks = (b ? 1 : 0);
+ this.stage = (b ? 1 : 0);
+ vl -= 0.2;
+ }
+ } else if (packet instanceof PacketPlayInBlockPlace) {
+ if (this.stage == 1) {
+ ++this.stage;
+ } else {
+ final boolean b2 = false;
+ this.looks = (b2 ? 1 : 0);
+ this.stage = (b2 ? 1 : 0);
+ }
+ } else if (packet instanceof PacketPlayInArmAnimation) {
+ if (this.stage == 2) {
+ ++this.stage;
+ } else {
+ final boolean b3 = false;
+ this.looks = (b3 ? 1 : 0);
+ this.stage = (b3 ? 1 : 0);
+ vl -= 0.2;
+ }
+ } else if (packet instanceof PacketPlayInFlying.PacketPlayInPositionLook || packet instanceof PacketPlayInFlying.PacketPlayInPosition) {
+ if (this.stage == 3) {
+ if (++this.looks == 3) {
+ this.stage = 4;
+ this.looks = 0;
+ }
+ } else {
+ final boolean b4 = false;
+ this.looks = (b4 ? 1 : 0);
+ this.stage = (b4 ? 1 : 0);
+ }
+ }
+
+ this.setVl(vl);
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/step/StepA.java b/src/main/java/me/joeleoli/fairfight/check/impl/step/StepA.java
new file mode 100644
index 0000000..e45b521
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/step/StepA.java
@@ -0,0 +1,25 @@
+package me.joeleoli.fairfight.check.impl.step;
+
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.fairfight.util.update.PositionUpdate;
+import org.bukkit.entity.Player;
+import me.joeleoli.fairfight.check.checks.PositionCheck;
+
+public class StepA extends PositionCheck {
+
+ public StepA(PlayerData playerData) {
+ super(playerData, "Step (Check 1)");
+ }
+
+ @Override
+ public void handleCheck(final Player player, final PositionUpdate update) {
+ double height = 0.9;
+ double difference = update.getTo().getY() - update.getFrom().getY();
+
+ if (difference > height) {
+ this.alert(AlertType.EXPERIMENTAL, player, "", true);
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/timer/TimerA.java b/src/main/java/me/joeleoli/fairfight/check/impl/timer/TimerA.java
new file mode 100644
index 0000000..02fcf5f
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/timer/TimerA.java
@@ -0,0 +1,53 @@
+package me.joeleoli.fairfight.check.impl.timer;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+
+import org.bukkit.entity.Player;
+
+import java.util.Deque;
+import java.util.LinkedList;
+
+public class TimerA extends PacketCheck {
+
+ private final Deque delays;
+ private long lastPacketTime;
+
+ public TimerA(PlayerData playerData) {
+ super(playerData, "Timer");
+ this.delays = new LinkedList<>();
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInFlying && !this.playerData.isAllowTeleport() && System.currentTimeMillis()
+ - this.playerData.getLastDelayedMovePacket() > 220L) {
+ this.delays.add(System.currentTimeMillis() - this.lastPacketTime);
+ if (this.delays.size() == 40) {
+ double average = 0.0;
+ for (final long l : this.delays) {
+ average += l;
+ }
+ average /= this.delays.size();
+ double vl = this.getVl();
+ if (average <= 49.0) {
+ if ((vl += 1.25) >= 4.0 && this.alert(AlertType.RELEASE, player, String.format("AVG %.3f. R %.2f." +
+ " VL %.2f.", average, 50.0 / average, vl), false) && !this.playerData.isBanning() && vl
+ >= 20.0) {
+ this.ban(player);
+ }
+ } else {
+ vl -= 0.5;
+ }
+ this.setVl(vl);
+ this.delays.clear();
+ }
+ this.lastPacketTime = System.currentTimeMillis();
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/vclip/VClipA.java b/src/main/java/me/joeleoli/fairfight/check/impl/vclip/VClipA.java
new file mode 100644
index 0000000..376a850
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/vclip/VClipA.java
@@ -0,0 +1,26 @@
+package me.joeleoli.fairfight.check.impl.vclip;
+
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.fairfight.util.nucleus.BlockUtil;
+import me.joeleoli.fairfight.util.update.PositionUpdate;
+import me.joeleoli.fairfight.check.checks.PositionCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+
+import org.bukkit.entity.Player;
+
+public class VClipA extends PositionCheck {
+
+ public VClipA(PlayerData playerData) {
+ super(playerData, "V-Clip (Check 1)");
+ }
+
+ @Override
+ public void handleCheck(final Player player, final PositionUpdate update) {
+ double difference = update.getTo().getY() - update.getFrom().getY();
+ if (difference >= 2.0 && !BlockUtil.isBlockFaceAir(player)) {
+ player.teleport(update.getFrom());
+ this.alert(AlertType.RELEASE, player, "", true);
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/vclip/VClipB.java b/src/main/java/me/joeleoli/fairfight/check/impl/vclip/VClipB.java
new file mode 100644
index 0000000..f83fd2d
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/vclip/VClipB.java
@@ -0,0 +1,26 @@
+package me.joeleoli.fairfight.check.impl.vclip;
+
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.fairfight.util.nucleus.BlockUtil;
+import me.joeleoli.fairfight.util.update.PositionUpdate;
+import org.bukkit.entity.Player;
+import me.joeleoli.fairfight.check.checks.PositionCheck;
+
+public class VClipB extends PositionCheck {
+
+ public VClipB(PlayerData playerData) {
+ super(playerData, "V-Clip (Check 2)");
+ }
+
+ @Override
+ public void handleCheck(final Player player, final PositionUpdate update) {
+
+ final double difference = update.getTo().getY() - update.getFrom().getY();
+
+ if (difference >= 2.0 && BlockUtil.isSlab(player)) {
+ player.teleport(update.getFrom());
+ this.alert(AlertType.RELEASE, player, "", true);
+ }
+ }
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/velocity/VelocityA.java b/src/main/java/me/joeleoli/fairfight/check/impl/velocity/VelocityA.java
new file mode 100644
index 0000000..a710c8a
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/velocity/VelocityA.java
@@ -0,0 +1,48 @@
+package me.joeleoli.fairfight.check.impl.velocity;
+
+import me.joeleoli.fairfight.check.checks.PositionCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.fairfight.util.MathUtil;
+import me.joeleoli.fairfight.util.update.PositionUpdate;
+
+import org.bukkit.entity.Player;
+
+public class VelocityA extends PositionCheck {
+
+ public VelocityA(PlayerData playerData) {
+ super(playerData, "Velocity (Check 1)");
+ }
+
+ @Override
+ public void handleCheck(final Player player, final PositionUpdate update) {
+ int vl = (int) this.getVl();
+
+ if (this.playerData.getVelocityY() > 0.0 && !this.playerData.isUnderBlock() && !this.playerData
+ .isWasUnderBlock() && !this.playerData.isInLiquid() && !this.playerData.isWasInLiquid() && !this
+ .playerData.isInWeb() && !this.playerData.isWasInWeb() && System.currentTimeMillis() - this
+ .playerData.getLastDelayedMovePacket() > 220L && System.currentTimeMillis() - this.playerData
+ .getLastMovePacket().getTimestamp() < 110L) {
+ final int threshold = 10 + MathUtil.pingFormula(this.playerData.getPing()) * 2;
+
+ if (++vl >= threshold) {
+ if (this.alert(AlertType.RELEASE, player, "VL " + vl + ".", true)) {
+ final int violations = this.playerData.getViolations(this, 60000L);
+
+ if (!this.playerData.isBanning() && violations > Math.max(this.playerData.getPing() / 10L, 15L)) {
+ this.ban(player);
+ }
+ }
+
+ this.playerData.setVelocityY(0.0);
+
+ vl = 0;
+ }
+ } else {
+ vl = 0;
+ }
+
+ this.setVl(vl);
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/velocity/VelocityB.java b/src/main/java/me/joeleoli/fairfight/check/impl/velocity/VelocityB.java
new file mode 100644
index 0000000..c26d402
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/velocity/VelocityB.java
@@ -0,0 +1,42 @@
+package me.joeleoli.fairfight.check.impl.velocity;
+
+import me.joeleoli.fairfight.check.checks.PositionCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.fairfight.util.update.PositionUpdate;
+
+import org.bukkit.entity.Player;
+
+public class VelocityB extends PositionCheck {
+
+ public VelocityB(PlayerData playerData) {
+ super(playerData, "Velocity (Check 2)");
+ }
+
+ @Override
+ public void handleCheck(final Player player, final PositionUpdate update) {
+ final double offsetY = update.getTo().getY() - update.getFrom().getY();
+ if (this.playerData.getVelocityY() > 0.0 && this.playerData.isWasOnGround() && !this.playerData.isUnderBlock
+ () && !this.playerData.isWasUnderBlock() && !this.playerData.isInLiquid() && !this.playerData
+ .isWasInLiquid() && !this.playerData.isInWeb() && !this.playerData.isWasInWeb() && !this.playerData
+ .isOnStairs() && offsetY > 0.0 && offsetY < 0.41999998688697815 && update.getFrom().getY() % 1.0 ==
+ 0.0) {
+ final double ratioY = offsetY / this.playerData.getVelocityY();
+ int vl = (int) this.getVl();
+
+ if (ratioY < 0.99) {
+ final int percent = (int) Math.round(ratioY * 100.0);
+
+ if (++vl >= 5 && this.alert(AlertType.RELEASE, player, "P " + percent + ". VL " + vl + ".", false) &&
+ !this.playerData.isBanning() && vl >= 15) {
+ this.ban(player);
+ }
+ } else {
+ --vl;
+ }
+
+ this.setVl(vl);
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/velocity/VelocityC.java b/src/main/java/me/joeleoli/fairfight/check/impl/velocity/VelocityC.java
new file mode 100644
index 0000000..1687baf
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/velocity/VelocityC.java
@@ -0,0 +1,46 @@
+package me.joeleoli.fairfight.check.impl.velocity;
+
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.fairfight.util.update.PositionUpdate;
+import net.minecraft.server.v1_8_R3.EntityPlayer;
+import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import me.joeleoli.fairfight.check.checks.PositionCheck;
+
+public class VelocityC extends PositionCheck {
+
+ public VelocityC(PlayerData playerData) {
+ super(playerData, "Velocity (Check 3)");
+ }
+
+ @Override
+ public void handleCheck(final Player player, final PositionUpdate update) {
+ double offsetY = update.getTo().getY() - update.getFrom().getY();
+ double offsetH = Math.hypot(update.getTo().getX() - update.getFrom().getX(),
+ update.getTo().getZ() - update.getFrom().getZ());
+
+ double velocityH = Math.hypot(this.playerData.getVelocityX(), this.playerData.getVelocityZ());
+
+ EntityPlayer entityPlayer = ((CraftPlayer) update.getPlayer()).getHandle();
+ if (this.playerData.getVelocityY() > 0.0 && this.playerData.isWasOnGround() &&
+ !this.playerData.isUnderBlock() && !this.playerData.isWasUnderBlock() && !this.playerData.isInLiquid() &&
+ !this.playerData.isWasInLiquid() && !this.playerData.isInWeb() && !this.playerData.isWasInWeb() &&
+ update.getFrom().getY() % 1.0 == 0.0 && offsetY > 0.0 && offsetY < 0.41999998688697815 &&
+ velocityH > 0.45 && !entityPlayer.world.c(entityPlayer.getBoundingBox().grow(1.0, 0.0, 1.0))) {
+ double ratio = offsetH / velocityH;
+ double vl = this.getVl();
+ if (ratio < 0.62) {
+ if ((vl += 1.1) >= 8.0 && this.alert(AlertType.RELEASE, player,
+ String.format("P %s. VL %.2f.", Math.round(ratio * 100.0), vl), false) &&
+ !this.playerData.isBanning() && vl >= 20.0) {
+ this.ban(player);
+ }
+ } else {
+ vl -= 0.4;
+ }
+ this.setVl(vl);
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/wtap/WTapA.java b/src/main/java/me/joeleoli/fairfight/check/impl/wtap/WTapA.java
new file mode 100644
index 0000000..75fd3cd
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/wtap/WTapA.java
@@ -0,0 +1,82 @@
+package me.joeleoli.fairfight.check.impl.wtap;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.Packet;
+import net.minecraft.server.v1_8_R3.PacketPlayInBlockDig;
+import net.minecraft.server.v1_8_R3.PacketPlayInEntityAction;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+
+import org.bukkit.entity.Player;
+
+import java.util.Deque;
+import java.util.LinkedList;
+
+public class WTapA extends PacketCheck {
+
+ private final Deque recentCounts;
+ private boolean release;
+ private int flyingCount;
+
+ public WTapA(PlayerData playerData) {
+ super(playerData, "Tap (Check 1)");
+
+ this.recentCounts = new LinkedList<>();
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInEntityAction) {
+ final PacketPlayInEntityAction.EnumPlayerAction playerAction = ((PacketPlayInEntityAction) packet).b();
+
+ if (playerAction == PacketPlayInEntityAction.EnumPlayerAction.START_SPRINTING) {
+ if (this.playerData.getLastAttackPacket() + 1000L > System.currentTimeMillis() && this.flyingCount < 10 && !this.release) {
+ this.recentCounts.add(this.flyingCount);
+
+ if (this.recentCounts.size() == 20) {
+ double average = 0.0;
+
+ for (final double flyingCount : this.recentCounts) {
+ average += flyingCount;
+ }
+
+ average /= this.recentCounts.size();
+
+ double stdDev = 0.0;
+
+ for (final long l : this.recentCounts) {
+ stdDev += Math.pow(l - average, 2.0);
+ }
+
+ stdDev /= this.recentCounts.size();
+ stdDev = Math.sqrt(stdDev);
+
+ double vl = this.getVl();
+
+ if (stdDev == 0.0) {
+ if ((vl += 1.2) >= 2.4) {
+ this.alert(AlertType.EXPERIMENTAL, player, String.format("STD %.2f, VL %.2f", stdDev, vl), false);
+ }
+ } else {
+ vl -= 2.0;
+ }
+
+ this.setVl(vl);
+ this.recentCounts.clear();
+ }
+ }
+ } else if (playerAction == PacketPlayInEntityAction.EnumPlayerAction.STOP_SPRINTING) {
+ this.flyingCount = 0;
+ }
+ } else if (packet instanceof PacketPlayInFlying) {
+ ++this.flyingCount;
+
+ this.release = false;
+ } else if (packet instanceof PacketPlayInBlockDig && ((PacketPlayInBlockDig) packet).c() == PacketPlayInBlockDig.EnumPlayerDigType.RELEASE_USE_ITEM) {
+ this.release = true;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/check/impl/wtap/WTapB.java b/src/main/java/me/joeleoli/fairfight/check/impl/wtap/WTapB.java
new file mode 100644
index 0000000..b15cb4c
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/check/impl/wtap/WTapB.java
@@ -0,0 +1,78 @@
+package me.joeleoli.fairfight.check.impl.wtap;
+
+import me.joeleoli.fairfight.check.checks.PacketCheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+
+import net.minecraft.server.v1_8_R3.*;
+
+import org.bukkit.entity.Player;
+
+import java.util.Deque;
+import java.util.LinkedList;
+
+public class WTapB extends PacketCheck {
+
+ private Deque recentCounts;
+ private boolean block;
+ private int flyingCount;
+
+ public WTapB(PlayerData playerData) {
+ super(playerData, "Tap (Check 2)");
+
+ this.recentCounts = new LinkedList<>();
+ }
+
+ @Override
+ public void handleCheck(Player player, Packet packet) {
+ if (packet instanceof PacketPlayInEntityAction) {
+ final PacketPlayInEntityAction.EnumPlayerAction playerAction = ((PacketPlayInEntityAction) packet).b();
+
+ if (playerAction == PacketPlayInEntityAction.EnumPlayerAction.STOP_SPRINTING && this.playerData
+ .getLastAttackPacket() + 1000L > System.currentTimeMillis() && this.flyingCount < 10 && !this
+ .block) {
+ this.recentCounts.add(this.flyingCount);
+
+ if (this.recentCounts.size() == 20) {
+ double average = 0.0;
+
+ for (final double flyingCount : this.recentCounts) {
+ average += flyingCount;
+ }
+
+ average /= this.recentCounts.size();
+
+ double stdDev = 0.0;
+
+ for (final long l : this.recentCounts) {
+ stdDev += Math.pow(l - average, 2.0);
+ }
+
+ stdDev /= this.recentCounts.size();
+ stdDev = Math.sqrt(stdDev);
+
+ double vl = this.getVl();
+
+ if (stdDev < 0.3) {
+ if ((vl += 1.2) >= 2.4) {
+ this.alert(AlertType.EXPERIMENTAL, player, String.format("STD %.2f, VL %.2f", stdDev, vl), false);
+ }
+ } else {
+ vl -= 2.0;
+ }
+ this.setVl(vl);
+ this.recentCounts.clear();
+ }
+ }
+ } else if (packet instanceof PacketPlayInUseEntity && ((PacketPlayInUseEntity) packet).a() == PacketPlayInUseEntity.EnumEntityUseAction.ATTACK) {
+ this.flyingCount = 0;
+ } else if (packet instanceof PacketPlayInFlying) {
+ ++this.flyingCount;
+
+ this.block = false;
+ } else if (packet instanceof PacketPlayInBlockPlace) {
+ this.block = true;
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/client/ClientManager.java b/src/main/java/me/joeleoli/fairfight/client/ClientManager.java
new file mode 100644
index 0000000..bf80998
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/client/ClientManager.java
@@ -0,0 +1,99 @@
+package me.joeleoli.fairfight.client;
+
+import com.google.common.collect.ImmutableMap;
+
+import me.joeleoli.fairfight.FairFight;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.fairfight.event.player.PlayerAlertEvent;
+
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringJoiner;
+
+public class ClientManager {
+
+ public static final Map BLACKLISTED_MODS;
+
+ static {
+ BLACKLISTED_MODS = ImmutableMap.of("MouseTweaks", "Mouse Tweaks", "Particle Mod", "Particle Mod", "npcmod", "NPC Mod");
+ }
+
+ private Set clientTypes;
+
+ public ClientManager() {
+ this.clientTypes = new HashSet<>();
+ this.clientTypes.add(new ModClientType("Ethylene", "ethylene", null));
+ this.clientTypes.add(new ModClientType("Ghost Client (Generic)", "gc", null));
+ this.clientTypes.add(new ModClientType("Merge Aimbot", "Aimbot", null));
+ this.clientTypes.add(new ModClientType("Cracked Vape v2.49", "mergeclient", null));
+ this.clientTypes.add(new ModClientType("Cracked Vape v2.50", "wigger", null));
+ this.clientTypes.add(new ModClientType("OpenComputers", "OpenComputers", "1.0"));
+ this.clientTypes.add(new ModClientType("Schematica Reach", "Schematica", "1.7.6.git"));
+ this.clientTypes.add(new ModClientType("TimeChanger Misplace", "timechanger", "1.0 "));
+ this.clientTypes.add(new ModClientType("TcpNoDelay Clients", "TcpNoDelayMod-2.0", "1.0"));
+ this.clientTypes.add(new PayloadClientType("Cracked Vape v2.06", "LOLIMAHCKER", true));
+ this.clientTypes.add(new PayloadClientType("Cracked Merge", "cock", true));
+ this.clientTypes.add(new PayloadClientType("BspkrsCore Client 1", "customGuiOpenBspkrs", true));
+ this.clientTypes.add(new PayloadClientType("BspkrsCore Client 2", "0SO1Lk2KASxzsd", true));
+ this.clientTypes.add(new PayloadClientType("BspkrsCore Client 3", "mincraftpvphcker", true));
+ this.clientTypes.add(new PayloadClientType("Cracked Incognito", "lmaohax", true));
+ this.clientTypes.add(new PayloadClientType("Old TimeChanger Misplace", "MCnetHandler", true));
+ this.clientTypes.add(new PayloadClientType("OCMC", "OCMC", false));
+ this.clientTypes.add(new PayloadClientType("CheatBreaker", "CB-Client", false));
+ this.clientTypes.add(new PayloadClientType("Cosmic Client", "CC", false));
+ this.clientTypes.add(new PayloadClientType("Labymod", "LABYMOD", false));
+ }
+
+ public void onModList(PlayerData playerData, Player player, Map mods) {
+ ClientType type = null;
+
+ typeCheck:
+ for (Map.Entry entry : mods.entrySet()) {
+ for (ClientType clientType : this.clientTypes) {
+ if (clientType instanceof ModClientType) {
+ final ModClientType modClientType = (ModClientType) clientType;
+
+ if (modClientType.getModId().equalsIgnoreCase(entry.getKey()) && modClientType.getModVersion().equalsIgnoreCase(entry.getValue())) {
+ type = modClientType;
+ break typeCheck;
+ }
+ }
+ }
+ }
+
+ if (type == null) {
+ type = EnumClientType.FORGE;
+
+ final StringJoiner blacklisted = new StringJoiner(", ");
+ boolean kick = false;
+
+ for (String modId : ClientManager.BLACKLISTED_MODS.keySet()) {
+ if (mods.containsKey(modId)) {
+ blacklisted.add(ClientManager.BLACKLISTED_MODS.get(modId));
+ kick = true;
+ }
+ }
+
+ if (kick) {
+ player.kickPlayer(ChatColor.RED + "[FairFight] Blacklisted modification: " + blacklisted.toString());
+ }
+ }
+
+ playerData.setClient(type);
+ playerData.setForgeMods(mods);
+
+ if (type.isHacked()) {
+ playerData.setRandomBanRate(500.0);
+ playerData.setRandomBanReason(type.getName());
+ playerData.setRandomBan(true);
+
+ FairFight.getInstance().getServer().getPluginManager().callEvent(new PlayerAlertEvent(AlertType.RELEASE, player, type.getName(), null));
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/client/ClientType.java b/src/main/java/me/joeleoli/fairfight/client/ClientType.java
new file mode 100644
index 0000000..5647737
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/client/ClientType.java
@@ -0,0 +1,9 @@
+package me.joeleoli.fairfight.client;
+
+public interface ClientType {
+
+ String getName();
+
+ boolean isHacked();
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/client/EnumClientType.java b/src/main/java/me/joeleoli/fairfight/client/EnumClientType.java
new file mode 100644
index 0000000..bd172a6
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/client/EnumClientType.java
@@ -0,0 +1,36 @@
+package me.joeleoli.fairfight.client;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum EnumClientType implements ClientType {
+
+ COSMIC_CLIENT(false, "Cosmic-Client"),
+ CHEAT_BREAKER(false, "Cheat-Breaker"),
+ VANILLA(false, "Regular-Client"),
+ FORGE(false, "Forge-Client"),
+ OCMC(false, "OCMC-Client"),
+ HACKED_CLIENT_A(true, "Hacked-Client"),
+ HACKED_CLIENT_B(true, "Hacked-Client"),
+ HACKED_CLIENT_C(true, "Hacked-Client"),
+ HACKED_CLIENT_C2(true, "Hacked-Client"),
+ HACKED_CLIENT_C3(true, "Hacked-Client"),
+ HACKED_CLIENT_D(true, "Hacked-Client"),
+ HACKED_CLIENT_E(true, "Hacked-Client"),
+ HACKED_CLIENT_E2(true, "Hacked-Client"),
+ HACKED_CLIENT_F(true, "Hacked-Client"),
+ HACKED_CLIENT_G(true, "Hacked-Client"),
+ HACKED_CLIENT_H(true, "Hacked-Client"),
+ HACKED_CLIENT_I(true, "Hacked-Client"),
+ HACKED_CLIENT_J(true, "Hacked-Client"),
+ HACKED_CLIENT_K(true, "Hacked-Client"),
+ HACKED_CLIENT_L(true, "Hacked-Client"),
+ HACKED_CLIENT_L2(true, "Hacked-Client"),
+ HACKED_CLIENT_M(true, "Hacked-Client");
+
+ private boolean hacked;
+ private String name;
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/client/ModClientType.java b/src/main/java/me/joeleoli/fairfight/client/ModClientType.java
new file mode 100644
index 0000000..e9261ad
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/client/ModClientType.java
@@ -0,0 +1,19 @@
+package me.joeleoli.fairfight.client;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public class ModClientType implements ClientType {
+
+ private final String name;
+ private final String modId;
+ private final String modVersion;
+
+ @Override
+ public boolean isHacked() {
+ return true;
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/client/PayloadClientType.java b/src/main/java/me/joeleoli/fairfight/client/PayloadClientType.java
new file mode 100644
index 0000000..e8e8669
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/client/PayloadClientType.java
@@ -0,0 +1,14 @@
+package me.joeleoli.fairfight.client;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public class PayloadClientType implements ClientType {
+
+ private final String name;
+ private final String payload;
+ private final boolean hacked;
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/command/FairFightCommand.java b/src/main/java/me/joeleoli/fairfight/command/FairFightCommand.java
new file mode 100644
index 0000000..26820c1
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/command/FairFightCommand.java
@@ -0,0 +1,63 @@
+package me.joeleoli.fairfight.command;
+
+import me.joeleoli.fairfight.FairFight;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.util.zoot.util.CC;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+public class FairFightCommand implements CommandExecutor {
+ @Override
+ public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
+ if (sender instanceof Player) {
+ Player player = (Player) sender;
+ if (args.length == 0) {
+ player.sendMessage(CC.translate("&6/fairfight check "));
+ player.sendMessage(CC.translate("&6/fairfight client "));
+ player.sendMessage(CC.translate("&6/fairfight alerts"));
+ } else if (args[0].equalsIgnoreCase("check") && args.length >= 2) {
+ boolean contains = FairFight.getInstance().getDisabledChecks().remove(args[1].toUpperCase());
+
+ if (contains) {
+ player.sendMessage(CC.GREEN + "The filter `" + args[1] + "` has been removed.");
+ } else {
+ FairFight.getInstance().getDisabledChecks().add(args[1].toUpperCase());
+ player.sendMessage(CC.GREEN + "The filter `" + args[1] + "` has been added.");
+ }
+ } else if (args[0].equalsIgnoreCase("client") && args.length >= 2) {
+ Player target = Bukkit.getPlayer(args[1]);
+
+ if (target != null) {
+ final PlayerData playerData = FairFight.getInstance().getPlayerDataManager().getPlayerData(target);
+
+ if (playerData.getClient() != null) {
+ player.sendMessage(CC.PINK + target.getName() + CC.YELLOW + " is on " + CC.PINK + playerData.getClient().getName());
+ } else {
+ player.sendMessage(CC.PINK + target.getName() + CC.YELLOW + " is on " + CC.PINK + "Unknown");
+ }
+ } else {
+ player.sendMessage(CC.translate("&cThat player is not online."));
+ }
+ } else if (args[0].equalsIgnoreCase("alerts")) {
+ boolean receiving = FairFight.getInstance().toggleAlerts(player);
+
+ if (receiving) {
+ player.sendMessage(CC.GREEN + "You enabled FairFight alerts.");
+ } else {
+ player.sendMessage(CC.RED + "You disabled FairFight alerts.");
+ }
+ } else {
+ player.sendMessage(CC.translate("&6/fairfight check "));
+ player.sendMessage(CC.translate("&6/fairfight client "));
+ player.sendMessage(CC.translate("&6/fairfight alerts"));
+ }
+ } else {
+ sender.sendMessage(CC.translate("&cThis command is for players only!"));
+ }
+
+ return true;
+ }
+}
diff --git a/src/main/java/me/joeleoli/fairfight/event/BaseEvent.java b/src/main/java/me/joeleoli/fairfight/event/BaseEvent.java
new file mode 100644
index 0000000..fb40bbf
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/event/BaseEvent.java
@@ -0,0 +1,26 @@
+package me.joeleoli.fairfight.event;
+
+import org.bukkit.Bukkit;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+public class BaseEvent extends Event {
+
+ private static final HandlerList handlers = new HandlerList();
+
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
+
+ @Override
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ public boolean call() {
+ Bukkit.getServer().getPluginManager().callEvent(this);
+ return this instanceof Cancellable && ((Cancellable) this).isCancelled();
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/event/BungeeReceivedEvent.java b/src/main/java/me/joeleoli/fairfight/event/BungeeReceivedEvent.java
new file mode 100644
index 0000000..448f6ad
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/event/BungeeReceivedEvent.java
@@ -0,0 +1,22 @@
+package me.joeleoli.fairfight.event;
+import lombok.Getter;
+import org.bukkit.entity.Player;
+
+@Getter
+public class BungeeReceivedEvent extends PlayerEvent {
+
+ private final String channel;
+ private final String message;
+
+ private final byte[] messageBytes;
+ private final boolean isValid;
+
+ public BungeeReceivedEvent(Player player, String channel, String message, byte[] messageBytes, boolean isValid) {
+ super(player);
+ this.channel = channel;
+ this.message = message;
+ this.messageBytes = messageBytes;
+ this.isValid = isValid;
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/event/ModListRetrieveEvent.java b/src/main/java/me/joeleoli/fairfight/event/ModListRetrieveEvent.java
new file mode 100644
index 0000000..290475a
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/event/ModListRetrieveEvent.java
@@ -0,0 +1,18 @@
+package me.joeleoli.fairfight.event;
+
+import java.util.Map;
+import lombok.Getter;
+import org.bukkit.entity.Player;
+
+@Getter
+public class ModListRetrieveEvent extends PlayerEvent {
+
+ private final Map mods;
+
+ public ModListRetrieveEvent(Player player, Map mods) {
+ super(player);
+
+ this.mods = mods;
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/event/PlayerEvent.java b/src/main/java/me/joeleoli/fairfight/event/PlayerEvent.java
new file mode 100644
index 0000000..3548917
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/event/PlayerEvent.java
@@ -0,0 +1,22 @@
+package me.joeleoli.fairfight.event;
+
+import java.util.UUID;
+import lombok.Getter;
+import org.bukkit.entity.Player;
+
+@Getter
+public class PlayerEvent extends BaseEvent {
+ private Player player;
+
+ public PlayerEvent(Player player) {
+ this.player = player;
+ }
+
+ public Player getPlayer() {
+ return player;
+ }
+
+ public UUID getUniqueId() {
+ return player.getUniqueId();
+ }
+}
diff --git a/src/main/java/me/joeleoli/fairfight/event/player/AlertType.java b/src/main/java/me/joeleoli/fairfight/event/player/AlertType.java
new file mode 100644
index 0000000..fe973d6
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/event/player/AlertType.java
@@ -0,0 +1,9 @@
+package me.joeleoli.fairfight.event.player;
+
+public enum AlertType {
+
+ RELEASE,
+ EXPERIMENTAL,
+ DEVELOPMENT
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/event/player/PlayerAlertEvent.java b/src/main/java/me/joeleoli/fairfight/event/player/PlayerAlertEvent.java
new file mode 100644
index 0000000..d16e3f7
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/event/player/PlayerAlertEvent.java
@@ -0,0 +1,42 @@
+package me.joeleoli.fairfight.event.player;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+@Getter
+public class PlayerAlertEvent extends Event implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST;
+
+ static {
+ HANDLER_LIST = new HandlerList();
+ }
+
+ private final AlertType alertType;
+ private final Player player;
+ private final String checkName;
+ private final String extra;
+ @Setter
+ private boolean cancelled;
+
+ public PlayerAlertEvent(AlertType alertType, Player player, String checkName, String extra) {
+ this.alertType = alertType;
+ this.player = player;
+ this.checkName = checkName;
+ this.extra = extra;
+ }
+
+ public HandlerList getHandlers() {
+ return PlayerAlertEvent.HANDLER_LIST;
+ }
+
+ public static HandlerList getHandlerList() {
+ return PlayerAlertEvent.HANDLER_LIST;
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/event/player/PlayerBanEvent.java b/src/main/java/me/joeleoli/fairfight/event/player/PlayerBanEvent.java
new file mode 100644
index 0000000..6232a93
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/event/player/PlayerBanEvent.java
@@ -0,0 +1,35 @@
+package me.joeleoli.fairfight.event.player;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.bukkit.event.*;
+import org.bukkit.entity.*;
+
+@Getter
+public class PlayerBanEvent extends Event implements Cancellable {
+
+ private static final HandlerList HANDLER_LIST;
+
+ static {
+ HANDLER_LIST = new HandlerList();
+ }
+
+ private Player player;
+ private String reason;
+ @Setter
+ private boolean cancelled;
+
+ public PlayerBanEvent(final Player player, final String reason) {
+ this.player = player;
+ this.reason = reason;
+ }
+
+ public static HandlerList getHandlerList() {
+ return PlayerBanEvent.HANDLER_LIST;
+ }
+
+ public HandlerList getHandlers() {
+ return PlayerBanEvent.HANDLER_LIST;
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/handler/CustomMovementHandler.java b/src/main/java/me/joeleoli/fairfight/handler/CustomMovementHandler.java
new file mode 100644
index 0000000..98328be
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/handler/CustomMovementHandler.java
@@ -0,0 +1,149 @@
+package me.joeleoli.fairfight.handler;
+
+import lombok.AllArgsConstructor;
+
+import me.joeleoli.fairfight.check.ICheck;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.util.nucleus.BlockUtil;
+import me.joeleoli.fairfight.util.update.PositionUpdate;
+import me.joeleoli.fairfight.util.update.RotationUpdate;
+import me.joeleoli.ragespigot.handler.MovementHandler;
+import me.joeleoli.fairfight.FairFight;
+
+import net.minecraft.server.v1_8_R3.BlockPosition;
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+
+import org.bukkit.Location;
+import org.bukkit.entity.Player;
+
+@AllArgsConstructor
+public class CustomMovementHandler implements MovementHandler {
+
+ private final FairFight plugin;
+
+ public void handleUpdateLocation(Player player, Location to, Location from, PacketPlayInFlying packet) {
+ if (player.getAllowFlight()) {
+ return;
+ }
+
+ if (player.isInsideVehicle()) {
+ return;
+ }
+
+ if (to.getY() < 2.0) {
+ return;
+ }
+
+ if (!player.getWorld().isChunkLoaded(to.getBlockX() >> 4, to.getBlockZ() >> 4)) {
+ return;
+ }
+
+ final PlayerData playerData = this.plugin.getPlayerDataManager().getPlayerData(player);
+
+ if (playerData == null) {
+ return;
+ }
+
+ playerData.setWasOnGround(playerData.isOnGround());
+ playerData.setWasInLiquid(playerData.isInLiquid());
+ playerData.setWasUnderBlock(playerData.isUnderBlock());
+ playerData.setWasInWeb(playerData.isInWeb());
+ playerData.setOnGround(BlockUtil.isOnGround(to, 0) || BlockUtil.isOnGround(to, 1));
+
+ if (!playerData.isOnGround()) {
+ positions:
+ for (BlockPosition position : playerData.getFakeBlocks()) {
+ int x = position.getX();
+ int z = position.getZ();
+
+ int blockX = to.getBlock().getX();
+ int blockZ = to.getBlock().getZ();
+
+ for (int xOffset = -1; xOffset <= 1; xOffset++) {
+ for (int zOffset = -1; zOffset <= 1; zOffset++) {
+ if (x == blockX + xOffset && z == blockZ + zOffset) {
+ int y = position.getY();
+ int pY = to.getBlock().getY();
+
+ if (pY - y <= 1 && pY > y) {
+ playerData.setOnGround(true);
+ }
+
+ if (playerData.isOnGround()) {
+ break positions;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (playerData.isOnGround()) {
+ playerData.setLastGroundY(to.getY());
+ }
+
+ playerData.setInLiquid(BlockUtil.isOnLiquid(to, 0) || BlockUtil.isOnLiquid(to, 1) || BlockUtil.isOnLiquid(to, -1));
+ playerData.setInWeb(BlockUtil.isOnWeb(to, 0));
+ playerData.setOnIce(BlockUtil.isOnIce(to, 1) || BlockUtil.isOnIce(to, 2));
+
+ if (playerData.isOnIce()) {
+ playerData.setMovementsSinceIce(0);
+ } else {
+ playerData.setMovementsSinceIce(playerData.getMovementsSinceIce() + 1);
+ }
+
+ playerData.setOnStairs(BlockUtil.isOnStairs(to, 0) || BlockUtil.isOnStairs(to, 1));
+ playerData.setOnCarpet(BlockUtil.isOnCarpet(to, 0) || BlockUtil.isOnCarpet(to, 1));
+ playerData.setUnderBlock(BlockUtil.isOnGround(to, -2));
+
+ if (playerData.isUnderBlock()) {
+ playerData.setMovementsSinceUnderBlock(0);
+ } else {
+ playerData.setMovementsSinceUnderBlock(playerData.getMovementsSinceUnderBlock() + 1);
+ }
+
+ if (to.getY() != from.getY() && playerData.getVelocityV() > 0) {
+ playerData.setVelocityV(playerData.getVelocityV() - 1);
+ }
+
+ if (Math.hypot(to.getX() - from.getX(), to.getZ() - from.getZ()) > 0.0 && playerData.getVelocityH() > 0) {
+ playerData.setVelocityH(playerData.getVelocityH() - 1);
+ }
+
+ for (final Class extends ICheck> checkClass : PlayerData.CHECKS) {
+ if (!FairFight.getInstance().getDisabledChecks().contains(checkClass.getSimpleName().toUpperCase())) {
+ final ICheck check = playerData.getCheck(checkClass);
+ if (check != null && check.getType() == PositionUpdate.class) {
+ check.handleCheck(player, new PositionUpdate(player, to, from, packet));
+ }
+ }
+ }
+
+ if (playerData.getVelocityY() > 0.0 && to.getY() > from.getY()) {
+ playerData.setVelocityY(0.0);
+ }
+ }
+
+ public void handleUpdateRotation(final Player player, final Location to, final Location from, final PacketPlayInFlying packet) {
+ if (player.getAllowFlight()) {
+ return;
+ }
+
+ final PlayerData playerData = this.plugin.getPlayerDataManager().getPlayerData(player);
+
+ if (playerData == null) {
+ return;
+ }
+
+ for (final Class extends ICheck> checkClass : PlayerData.CHECKS) {
+ if (!FairFight.getInstance().getDisabledChecks().contains(checkClass.getSimpleName().toUpperCase())) {
+ final ICheck check = playerData.getCheck(checkClass);
+
+ if (check != null && check.getType() == RotationUpdate.class) {
+ check.handleCheck(player, new RotationUpdate(player, to, from, packet));
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/handler/CustomPacketHandler.java b/src/main/java/me/joeleoli/fairfight/handler/CustomPacketHandler.java
new file mode 100644
index 0000000..c66eed7
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/handler/CustomPacketHandler.java
@@ -0,0 +1,619 @@
+package me.joeleoli.fairfight.handler;
+
+import lombok.AllArgsConstructor;
+
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.ragespigot.handler.PacketHandler;
+import me.joeleoli.fairfight.FairFight;
+import me.joeleoli.fairfight.check.ICheck;
+import me.joeleoli.fairfight.client.EnumClientType;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.player.PlayerAlertEvent;
+import me.joeleoli.fairfight.event.player.PlayerBanEvent;
+import me.joeleoli.fairfight.util.CustomLocation;
+
+import net.minecraft.server.v1_8_R3.*;
+
+import org.apache.commons.io.Charsets;
+import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
+import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@AllArgsConstructor
+public class CustomPacketHandler implements PacketHandler {
+
+ private static Field positionField;
+
+ private static final List INSTANT_BREAK_BLOCKS = Arrays.asList(
+ "reeds", "waterlily", "deadbush", "flower", "doubleplant", "tallgrass"
+ );
+
+ static {
+ try {
+ positionField = PacketPlayOutBlockChange.class.getDeclaredField("a");
+ positionField.setAccessible(true);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private final FairFight plugin;
+
+ public void handleReceivedPacket(PlayerConnection playerConnection, Packet packet) {
+ try {
+ final Player player = playerConnection.getPlayer();
+ final PlayerData playerData = this.plugin.getPlayerDataManager().getPlayerData(player);
+
+ if (playerData == null) {
+ return;
+ }
+
+ if (playerData.isSniffing()) {
+ this.handleSniffedPacket(packet, playerData);
+ }
+
+ final String simpleName = packet.getClass().getSimpleName();
+
+ switch (simpleName) {
+ case "PacketPlayInCustomPayload": {
+ if (!playerData.getClient().isHacked()) {
+ this.handleCustomPayload((PacketPlayInCustomPayload) packet, playerData, player);
+ break;
+ }
+ break;
+ }
+ case "PacketPlayInPosition":
+ case "PacketPlayInPositionLook":
+ case "PacketPlayInLook":
+ case "PacketPlayInFlying": {
+ this.handleFlyPacket((PacketPlayInFlying)packet, playerData);
+ break;
+ }
+ case "PacketPlayInKeepAlive": {
+ this.handleKeepAlive((PacketPlayInKeepAlive)packet, playerData, player);
+ break;
+ }
+ case "PacketPlayInUseEntity": {
+ this.handleUseEntity((PacketPlayInUseEntity)packet, playerData, player);
+ break;
+ }
+ case "PacketPlayInBlockPlace": {
+ playerData.setPlacing(true);
+ break;
+ }
+ case "PacketPlayInCloseWindow": {
+ playerData.setInventoryOpen(false);
+ break;
+ }
+ case "PacketPlayInClientCommand": {
+ if (((PacketPlayInClientCommand)packet).a() == PacketPlayInClientCommand.EnumClientCommand.OPEN_INVENTORY_ACHIEVEMENT) {
+ playerData.setInventoryOpen(true);
+ break;
+ }
+ break;
+ }
+ case "PacketPlayInEntityAction": {
+ final PacketPlayInEntityAction.EnumPlayerAction actionType = ((PacketPlayInEntityAction)packet).b();
+ if (actionType == PacketPlayInEntityAction.EnumPlayerAction.START_SPRINTING) {
+ playerData.setSprinting(true);
+ break;
+ }
+ if (actionType == PacketPlayInEntityAction.EnumPlayerAction.STOP_SPRINTING) {
+ playerData.setSprinting(false);
+ break;
+ }
+ break;
+ }
+ case "PacketPlayInBlockDig": {
+ final PacketPlayInBlockDig.EnumPlayerDigType digType = ((PacketPlayInBlockDig)packet).c();
+
+ if (playerData.getFakeBlocks().contains(((PacketPlayInBlockDig) packet).a())) {
+ playerData.setInstantBreakDigging(false);
+ playerData.setFakeDigging(true);
+ playerData.setDigging(false);
+ } else {
+ playerData.setFakeDigging(false);
+
+ if (digType == PacketPlayInBlockDig.EnumPlayerDigType.START_DESTROY_BLOCK) {
+ Block block = ((CraftWorld) player.getWorld()).getHandle().c(((PacketPlayInBlockDig) packet).a());
+
+ String tile = block.a().replace("tile.", "");
+
+ if (INSTANT_BREAK_BLOCKS.contains(tile)) {
+ playerData.setInstantBreakDigging(true);
+ } else {
+ playerData.setInstantBreakDigging(false);
+ }
+
+ playerData.setDigging(true);
+ } else if (digType == PacketPlayInBlockDig.EnumPlayerDigType.ABORT_DESTROY_BLOCK ||
+ digType == PacketPlayInBlockDig.EnumPlayerDigType.STOP_DESTROY_BLOCK) {
+ playerData.setInstantBreakDigging(false);
+ playerData.setDigging(false);
+ }
+ }
+ break;
+ }
+ case "PacketPlayInArmAnimation": {
+ playerData.setLastAnimationPacket(System.currentTimeMillis());
+ break;
+ }
+ }
+
+ for (final Class extends ICheck> checkClass : PlayerData.CHECKS) {
+ if (!FairFight.getInstance().getDisabledChecks().contains(checkClass.getSimpleName().toUpperCase())) {
+ final ICheck check = (playerData.getCheck(checkClass));
+
+ if (check != null && check.getType() == Packet.class) {
+ check.handleCheck(playerConnection.getPlayer(), packet);
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void handleSentPacket(final PlayerConnection playerConnection, final Packet packet) {
+ try {
+ final Player player = playerConnection.getPlayer();
+ final PlayerData playerData = this.plugin.getPlayerDataManager().getPlayerData(player);
+
+ if (playerData == null) {
+ return;
+ }
+
+ final String simpleName = packet.getClass().getSimpleName();
+
+ switch (simpleName) {
+ case "PacketPlayOutEntityVelocity": {
+ this.handleVelocityOut((PacketPlayOutEntityVelocity)packet, playerData, player);
+ break;
+ }
+ case "PacketPlayOutExplosion": {
+ this.handleExplosionPacket((PacketPlayOutExplosion)packet, playerData);
+ break;
+ }
+ case "PacketPlayOutEntityLook":
+ case "PacketPlayOutRelEntityMove":
+ case "PacketPlayOutRelEntityMoveLook":
+ case "PacketPlayOutEntity": {
+ this.handleEntityPacket((PacketPlayOutEntity)packet, playerData, player);
+ break;
+ }
+ case "PacketPlayOutEntityTeleport": {
+ this.handleTeleportPacket((PacketPlayOutEntityTeleport)packet, playerData, player);
+ break;
+ }
+ case "PacketPlayOutPosition": {
+ this.handlePositionPacket((PacketPlayOutPosition)packet, playerData);
+ break;
+ }
+ case "PacketPlayOutKeepAlive": {
+ playerData.addKeepAliveTime(((PacketPlayOutKeepAlive)packet).getA());
+ break;
+ }
+ case "PacketPlayOutCloseWindow": {
+ if (!playerData.keepAliveExists(-1)) {
+ ((CraftPlayer)player).getHandle().playerConnection.sendPacket(new PacketPlayOutKeepAlive(-1));
+ break;
+ }
+
+ break;
+ }
+ case "PacketPlayOutMultiBlockChange":
+ for (PacketPlayOutMultiBlockChange.MultiBlockChangeInfo info : ((PacketPlayOutMultiBlockChange) packet).getB()) {
+ BlockPosition position = info.a();
+
+ String name = info.c().getBlock().toString().replace("Block{minecraft:", "").replace("}", "");
+
+ StackTraceElement[] elements = Thread.currentThread().getStackTrace();
+
+ if (elements.length == 19 && elements[3].getMethodName().equals("sendTo")) {
+ if (name.equals("air")) {
+ playerData.getFakeBlocks().remove(position);
+ } else {
+ playerData.getFakeBlocks().add(position);
+ }
+ }
+ }
+ break;
+ case "PacketPlayOutBlockChange":
+ BlockPosition position = (BlockPosition) positionField.get(packet);
+
+ String name = ((PacketPlayOutBlockChange) packet).block.getBlock().toString()
+ .replace("Block{minecraft:", "").replace("}", "");
+
+ StackTraceElement[] elements = Thread.currentThread().getStackTrace();
+
+ if (elements.length == 13 && elements[3].getMethodName().equals("sendBlockChange")) {
+ if (name.equals("air")) {
+ playerData.getFakeBlocks().remove(position);
+ } else {
+ playerData.getFakeBlocks().add(position);
+ }
+ }
+ break;
+ }
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void handleSniffedPacket(Packet packet, PlayerData playerData) {
+ try {
+ final StringBuilder builder = new StringBuilder();
+
+ builder.append(packet.getClass().getSimpleName());
+ builder.append(" (timestamp = ");
+ builder.append(System.currentTimeMillis());
+
+ final List fieldsList = new ArrayList<>();
+
+ fieldsList.addAll(Arrays.asList(packet.getClass().getDeclaredFields()));
+ fieldsList.addAll(Arrays.asList(packet.getClass().getSuperclass().getDeclaredFields()));
+
+ for (final Field field : fieldsList) {
+ if (field.getName().equalsIgnoreCase("timestamp")) {
+ continue;
+ }
+
+ field.setAccessible(true);
+ builder.append(", ");
+ builder.append(field.getName());
+ builder.append(" = ");
+ builder.append(field.get(packet));
+ }
+
+ builder.append(")");
+
+ playerData.getSniffedPacketBuilder().append(builder.toString());
+ playerData.getSniffedPacketBuilder().append("\n");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void handleCustomPayload(PacketPlayInCustomPayload packet, PlayerData playerData, Player player) {
+ final String a = packet.a();
+ int n = -1;
+ switch (a.hashCode()) {
+ case -1772699639: {
+ if (a.equals("LOLIMAHCKER")) {
+ n = 0;
+ break;
+ }
+ break;
+ }
+ case 3059156: {
+ if (a.equals("cock")) {
+ n = 1;
+ break;
+ }
+ break;
+ }
+ case 509975521: {
+ if (a.equals("customGuiOpenBspkrs")) {
+ n = 2;
+ break;
+ }
+ break;
+ }
+ case 1228162850: {
+ if (a.equals("0SO1Lk2KASxzsd")) {
+ n = 3;
+ break;
+ }
+ break;
+ }
+ case 633656225: {
+ if (a.equals("mincraftpvphcker")) {
+ n = 4;
+ break;
+ }
+ break;
+ }
+ case 279718608: {
+ if (a.equals("lmaohax")) {
+ n = 5;
+ break;
+ }
+ break;
+ }
+ case 1566847235: {
+ if (a.equals("MCnetHandler")) {
+ n = 6;
+ break;
+ }
+ break;
+ }
+ case 24251720: {
+ if (a.equals("L0LIMAHCKER")) {
+ n = 7;
+ break;
+ }
+ break;
+ }
+ case 2420330: {
+ if (a.equals("OCMC")) {
+ n = 8;
+ break;
+ }
+ break;
+ }
+ case 92413603: {
+ if (a.equals("REGISTER")) {
+ n = 9;
+ break;
+ }
+ break;
+ }
+ }
+
+ EnumClientType type;
+
+ clientCheck: {
+ switch (n) {
+ case 0: {
+ type = EnumClientType.HACKED_CLIENT_A;
+ break clientCheck;
+ }
+ case 1: {
+ type = EnumClientType.HACKED_CLIENT_B;
+ break clientCheck;
+ }
+ case 2: {
+ type = EnumClientType.HACKED_CLIENT_C;
+ break clientCheck;
+ }
+ case 3: {
+ type = EnumClientType.HACKED_CLIENT_C2;
+ break clientCheck;
+ }
+ case 4: {
+ type = EnumClientType.HACKED_CLIENT_C3;
+ break clientCheck;
+ }
+ case 5: {
+ type = EnumClientType.HACKED_CLIENT_D;
+ break clientCheck;
+ }
+ case 6: {
+ type = EnumClientType.HACKED_CLIENT_E;
+ break clientCheck;
+ }
+ case 7: {
+ type = EnumClientType.HACKED_CLIENT_M;
+ break clientCheck;
+ }
+ case 8: {
+ type = EnumClientType.OCMC;
+ break clientCheck;
+ }
+ case 9: {
+ try {
+ final String registerType = packet.b().toString(Charsets.UTF_8);
+
+ if (registerType.contains("CB-Client")) {
+ type = EnumClientType.CHEAT_BREAKER;
+ } else {
+ if (!registerType.equalsIgnoreCase("CC")) {
+ return;
+ }
+
+ type = EnumClientType.COSMIC_CLIENT;
+ }
+
+ break clientCheck;
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ return;
+ }
+ }
+ }
+
+ return;
+ }
+
+ playerData.setClient(type);
+
+ if (type.isHacked()) {
+ this.plugin.getServer().getPluginManager().callEvent(new PlayerAlertEvent(AlertType.RELEASE, player, type.getName(), null));
+
+ playerData.setRandomBanRate(500.0);
+ playerData.setRandomBanReason(type.getName());
+ playerData.setRandomBan(true);
+ }
+ }
+
+ private void handleFlyPacket(PacketPlayInFlying packet, PlayerData playerData) {
+ CustomLocation customLocation = new CustomLocation(packet.a(), packet.b(), packet.c(), packet.d(), packet.e());
+ CustomLocation lastLocation = playerData.getLastMovePacket();
+
+ if (lastLocation != null) {
+ if (!packet.g()) {
+ customLocation.setX(lastLocation.getX());
+ customLocation.setY(lastLocation.getY());
+ customLocation.setZ(lastLocation.getZ());
+ }
+
+ if (!packet.h()) {
+ customLocation.setYaw(lastLocation.getYaw());
+ customLocation.setPitch(lastLocation.getPitch());
+ }
+
+ if (System.currentTimeMillis() - lastLocation.getTimestamp() > 110L) {
+ playerData.setLastDelayedMovePacket(System.currentTimeMillis());
+ }
+ }
+
+ if (playerData.isSetInventoryOpen()) {
+ playerData.setInventoryOpen(false);
+ playerData.setSetInventoryOpen(false);
+ }
+
+ playerData.setLastMovePacket(customLocation);
+ playerData.setPlacing(false);
+ playerData.setAllowTeleport(false);
+
+ if (packet instanceof PacketPlayInFlying.PacketPlayInPositionLook && playerData.allowTeleport(customLocation)) {
+ playerData.setAllowTeleport(true);
+ }
+ }
+
+ private void handleKeepAlive(final PacketPlayInKeepAlive packet, final PlayerData playerData, final Player player) {
+ final int id = packet.a();
+
+ if (playerData.keepAliveExists(id)) {
+ if (id == -1) {
+ playerData.setSetInventoryOpen(true);
+ } else {
+ playerData.setPing(System.currentTimeMillis() - playerData.getKeepAliveTime(id));
+ }
+
+ playerData.removeKeepAliveTime(id);
+ } else if (id != 0) {
+ this.plugin.getServer().getPluginManager().callEvent(new PlayerAlertEvent(AlertType.RELEASE, player, "Illegal Packets", null));
+ }
+ }
+
+ private void handleUseEntity(final PacketPlayInUseEntity packet, final PlayerData playerData, final Player player) {
+ if (packet.a() == PacketPlayInUseEntity.EnumEntityUseAction.ATTACK) {
+ playerData.setLastAttackPacket(System.currentTimeMillis());
+
+ if (playerData.isSendingVape()) {
+ playerData.setSendingVape(false);
+ }
+
+ if (!playerData.isAttackedSinceVelocity()) {
+ playerData.setVelocityX(playerData.getVelocityX() * 0.6);
+ playerData.setVelocityZ(playerData.getVelocityZ() * 0.6);
+ playerData.setAttackedSinceVelocity(true);
+ }
+
+ if (!playerData.isBanning() && playerData.isRandomBan() && Math.random() * playerData.getRandomBanRate() < 1.0) {
+ playerData.setBanning(true);
+
+ this.plugin.getServer().getPluginManager().callEvent(new PlayerBanEvent(player, playerData.getRandomBanReason()));
+ }
+
+ final Entity targetEntity = packet.a(((CraftPlayer)player).getHandle().getWorld());
+
+ if (targetEntity instanceof EntityPlayer) {
+ final Player target = (Player) targetEntity.getBukkitEntity();
+ playerData.setLastTarget(target.getUniqueId());
+ }
+ }
+ }
+
+ private void handleVelocityOut(final PacketPlayOutEntityVelocity packet, final PlayerData playerData, final Player player) {
+ if (packet.getA() == player.getEntityId()) {
+ final double x = Math.abs(packet.getB() / 8000.0);
+ final double y = packet.getC() / 8000.0;
+ final double z = Math.abs(packet.getD() / 8000.0);
+ if (x > 0.0 || z > 0.0) {
+ playerData.setVelocityH((int)(((x + z) / 2.0 + 2.0) * 15.0));
+ }
+ if (y > 0.0) {
+ playerData.setVelocityV((int)(Math.pow(y + 2.0, 2.0) * 5.0));
+ if (playerData.isOnGround() && player.getLocation().getY() % 1.0 == 0.0) {
+ playerData.setVelocityX(x);
+ playerData.setVelocityY(y);
+ playerData.setVelocityZ(z);
+ playerData.setLastVelocity(System.currentTimeMillis());
+ playerData.setAttackedSinceVelocity(false);
+ }
+ }
+ }
+ }
+
+ private void handleExplosionPacket(PacketPlayOutExplosion packet, PlayerData playerData) {
+ final float x = Math.abs(packet.getF());
+ final float y = packet.getG();
+ final float z = Math.abs(packet.getH());
+
+ if (x > 0.0f || z > 0.0f) {
+ playerData.setVelocityH((int)(((x + z) / 2.0f + 2.0f) * 15.0f));
+ }
+ if (y > 0.0f) {
+ playerData.setVelocityV((int)(Math.pow(y + 2.0f, 2.0) * 5.0));
+ }
+ }
+
+ private void handleEntityPacket(PacketPlayOutEntity packet, PlayerData playerData, Player player) {
+ final Entity targetEntity = ((CraftPlayer)player).getHandle().getWorld().a(packet.getA());
+
+ if (targetEntity instanceof EntityPlayer) {
+ final Player target = (Player) targetEntity.getBukkitEntity();
+ final CustomLocation customLocation = playerData.getLastPlayerPacket(target.getUniqueId(), 1);
+
+ if (customLocation != null) {
+ final double x = packet.getB() / 32.0;
+ final double y = packet.getC() / 32.0;
+ final double z = packet.getD() / 32.0;
+ float yaw = packet.getE() * 360.0f / 256.0f;
+ float pitch = packet.getF() * 360.0f / 256.0f;
+
+ if (!packet.isH()) {
+ yaw = customLocation.getYaw();
+ pitch = customLocation.getPitch();
+ }
+
+ playerData.addPlayerPacket(target.getUniqueId(), new CustomLocation(customLocation.getX() + x, customLocation.getY() + y, customLocation.getZ() + z, yaw, pitch));
+ }
+ }
+ }
+
+ private void handleTeleportPacket(final PacketPlayOutEntityTeleport packet, final PlayerData playerData, final Player player) {
+ final Entity targetEntity = ((CraftPlayer)player).getHandle().getWorld().a(packet.getA());
+
+ if (targetEntity instanceof EntityPlayer) {
+ final Player target = (Player)targetEntity.getBukkitEntity();
+ double x = packet.getB() / 32.0;
+ double z = packet.getD() / 32.0;
+ final double y = packet.getC() / 32.0;
+ final float yaw = packet.getE() * 360.0f / 256.0f;
+ final float pitch = packet.getF() * 360.0f / 256.0f;
+
+ playerData.addPlayerPacket(target.getUniqueId(), new CustomLocation(x, y, z, yaw, pitch));
+ }
+ }
+
+ private void handlePositionPacket(final PacketPlayOutPosition packet, final PlayerData playerData) {
+ if (packet.getE() > 90.0f) {
+ packet.setE(90.0f);
+ } else if (packet.getE() < -90.0f) {
+ packet.setE(-90.0f);
+ } else if (packet.getE() == 0.0f) {
+ packet.setE(0.492832f);
+ }
+
+ playerData.setVelocityY(0.0);
+ playerData.setVelocityX(0.0);
+ playerData.setVelocityZ(0.0);
+ playerData.setAttackedSinceVelocity(false);
+ playerData.addTeleportLocation(new CustomLocation(packet.getA(), packet.getB(), packet.getC(), packet.getD(), packet.getE()));
+ }
+
+ private float getAngle(final double posX, final double posZ, final CustomLocation location) {
+ final double x = posX - location.getX();
+ final double z = posZ - location.getZ();
+ float newYaw = (float)Math.toDegrees(-Math.atan(x / z));
+
+ if (z < 0.0 && x < 0.0) {
+ newYaw = (float)(90.0 + Math.toDegrees(Math.atan(z / x)));
+ } else if (z < 0.0 && x > 0.0) {
+ newYaw = (float)(-90.0 + Math.toDegrees(Math.atan(z / x)));
+ }
+
+ return newYaw;
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/listener/BungeeListener.java b/src/main/java/me/joeleoli/fairfight/listener/BungeeListener.java
new file mode 100644
index 0000000..c7b84bf
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/listener/BungeeListener.java
@@ -0,0 +1,60 @@
+package me.joeleoli.fairfight.listener;
+
+import com.google.common.io.ByteArrayDataInput;
+import com.google.common.io.ByteStreams;
+
+import java.util.Map;
+
+import lombok.RequiredArgsConstructor;
+
+import me.joeleoli.fairfight.FairFight;
+import me.joeleoli.fairfight.event.BungeeReceivedEvent;
+import me.joeleoli.fairfight.event.ModListRetrieveEvent;
+
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.messaging.PluginMessageListener;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+
+@RequiredArgsConstructor
+public class BungeeListener implements PluginMessageListener {
+
+ private final FairFight plugin;
+
+ @Override
+ public void onPluginMessageReceived(String channel, Player player, byte[] message) {
+ if (!channel.equals("BungeeCord")) {
+ return;
+ }
+
+ final ByteArrayDataInput in = ByteStreams.newDataInput(message);
+ final String subChannel = in.readUTF();
+
+ if (subChannel.equals("ForgeMods")) {
+ try {
+ Map mods = (Map) new JSONParser().parse(in.readUTF());
+ ModListRetrieveEvent event = new ModListRetrieveEvent(player, mods);
+
+ this.plugin.getServer().getPluginManager().callEvent(event);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+
+ return;
+ }
+
+ final short len = in.readShort();
+ final byte[] messageBytes = new byte[len];
+
+ in.readFully(messageBytes);
+
+ ByteArrayDataInput dis = ByteStreams.newDataInput(messageBytes);
+ String data = dis.readUTF();
+ Long systemTime = Long.parseLong(data.split(":")[0]);
+
+ final BungeeReceivedEvent event = new BungeeReceivedEvent(player, subChannel, data.replace(systemTime + ":", ""), message, systemTime > System.currentTimeMillis());
+
+ this.plugin.getServer().getPluginManager().callEvent(event);
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/listener/ModListListener.java b/src/main/java/me/joeleoli/fairfight/listener/ModListListener.java
new file mode 100644
index 0000000..52d59dd
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/listener/ModListListener.java
@@ -0,0 +1,34 @@
+package me.joeleoli.fairfight.listener;
+
+import me.joeleoli.fairfight.FairFight;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.event.ModListRetrieveEvent;
+
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+
+import java.util.Map;
+
+public class ModListListener implements Listener {
+
+ @EventHandler
+ public void onModListRetrieve(ModListRetrieveEvent event) {
+ final Player player = event.getPlayer();
+
+ if (player == null) {
+ return;
+ }
+
+ final PlayerData playerData = FairFight.getInstance().getPlayerDataManager().getPlayerData(player);
+
+ if (playerData == null) {
+ return;
+ }
+
+ final Map mods = event.getMods();
+
+ FairFight.getInstance().getClientManager().onModList(playerData, player, mods);
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/listener/PlayerListener.java b/src/main/java/me/joeleoli/fairfight/listener/PlayerListener.java
new file mode 100644
index 0000000..1055bb0
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/listener/PlayerListener.java
@@ -0,0 +1,151 @@
+package me.joeleoli.fairfight.listener;
+
+import io.netty.buffer.Unpooled;
+import java.text.MessageFormat;
+import java.util.List;
+
+import me.joeleoli.fairfight.FairFight;
+import me.joeleoli.fairfight.event.player.AlertType;
+import me.joeleoli.fairfight.event.player.PlayerAlertEvent;
+import me.joeleoli.fairfight.event.player.PlayerBanEvent;
+import me.joeleoli.fairfight.mongo.FairFightLog;
+import me.joeleoli.fairfight.player.PlayerData;
+import me.joeleoli.fairfight.util.nucleus.util.TaskUtil;
+import me.joeleoli.fairfight.util.zoot.util.CC;
+import net.minecraft.server.v1_8_R3.MinecraftServer;
+import net.minecraft.server.v1_8_R3.PacketDataSerializer;
+import net.minecraft.server.v1_8_R3.PacketPlayOutCustomPayload;
+import net.minecraft.server.v1_8_R3.PlayerConnection;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerChangedWorldEvent;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.bukkit.event.player.PlayerTeleportEvent;
+
+public class PlayerListener implements Listener {
+
+ @EventHandler
+ public void onPlayerJoin(PlayerJoinEvent event) {
+ FairFight.getInstance().getPlayerDataManager().addPlayerData(event.getPlayer());
+
+ if (event.getPlayer().hasPermission("fairfight.alerts")) {
+ FairFight.getInstance().getReceivingAlerts().add(event.getPlayer().getUniqueId());
+ }
+
+ FairFight.getInstance().getServer().getScheduler().runTaskLaterAsynchronously(FairFight.getInstance(), () -> {
+ final PlayerConnection playerConnection = ((CraftPlayer) event.getPlayer()).getHandle().playerConnection;
+ final PacketPlayOutCustomPayload packetPlayOutCustomPayload = new PacketPlayOutCustomPayload("REGISTER",
+ new PacketDataSerializer(Unpooled.wrappedBuffer("CB-Client".getBytes()))
+ );
+ final PacketPlayOutCustomPayload packetPlayOutCustomPayload2 = new PacketPlayOutCustomPayload("REGISTER",
+ new PacketDataSerializer(Unpooled.wrappedBuffer("CC".getBytes()))
+ );
+
+ playerConnection.sendPacket(packetPlayOutCustomPayload);
+ playerConnection.sendPacket(packetPlayOutCustomPayload2);
+ }, 10L);
+ }
+
+ @EventHandler
+ public void onPlayerQuit(PlayerQuitEvent event) {
+ FairFight.getInstance().getReceivingAlerts().remove(event.getPlayer().getUniqueId());
+ }
+
+ @EventHandler
+ public void onPlayerTeleport(PlayerTeleportEvent event) {
+ final Player player = event.getPlayer();
+ final PlayerData playerData = FairFight.getInstance().getPlayerDataManager().getPlayerData(player);
+
+ if (playerData != null) {
+ playerData.setSendingVape(true);
+ }
+ }
+
+ @EventHandler
+ public void onPlayerChangedWorld(PlayerChangedWorldEvent event) {
+ final Player player = event.getPlayer();
+ final PlayerData playerData = FairFight.getInstance().getPlayerDataManager().getPlayerData(player);
+
+ if (playerData != null) {
+ playerData.setInventoryOpen(false);
+ }
+ }
+
+ @EventHandler
+ public void onPlayerAlert(PlayerAlertEvent event) {
+ if (!FairFight.getInstance().isAntiCheatEnabled()) {
+ event.setCancelled(true);
+ return;
+ }
+
+ final Player player = event.getPlayer();
+
+ if (player == null) {
+ return;
+ }
+
+ final PlayerData playerData = FairFight.getInstance().getPlayerDataManager().getPlayerData(player);
+
+ if (playerData == null) {
+ return;
+ }
+
+ final String extra = event.getExtra() == null ? "" : " (" + event.getExtra() + ")";
+ final String message = CC.translate(new MessageFormat(FairFight.getInstance().getConfig().getString("name") + " {0} &ehas flagged &b{1} &7(Ping: {2}){3}")
+ .format(new Object[]{
+ player.getName(), event.getCheckName(), player.getPing(), extra
+ // Profile.getProfiles().get(player.getUniqueId()).getColoredUsername(), event.getCheckName(), player.getPing(), extra
+ // NucleusAPI.getColoredName(player), event.getCheckName(), player.getPing(), extra
+ }));
+
+ if (event.getAlertType() == AlertType.RELEASE) {
+ for (Player onlinePlayer : FairFight.getInstance().getServer().getOnlinePlayers()) {
+ if (FairFight.getInstance().canAlert(onlinePlayer)) {
+ onlinePlayer.sendMessage(message);
+ }
+ }
+ }
+
+ FairFightLog.getQueue().add(new FairFightLog(
+ player.getUniqueId(),
+ event.getCheckName(),
+ playerData.getClient().getName(),
+ player.getPing(),
+ MinecraftServer.getServer().tps1.getAverage(),
+ System.currentTimeMillis()
+ ));
+ }
+
+ @EventHandler
+ public void onPlayerBan(PlayerBanEvent event) {
+ if (!FairFight.getInstance().isAntiCheatEnabled()) {
+ event.setCancelled(true);
+ return;
+ }
+
+ final Player player = event.getPlayer();
+
+ if (player == null) {
+ return;
+ }
+
+ final List messages = FairFight.getInstance().getConfig().getStringList("ban-broadcast");
+
+ for (String s : messages) {
+ Bukkit.getServer().broadcastMessage(ChatColor.translateAlternateColorCodes('&', s).replaceAll("%player%", player.getName()));
+ }
+
+ TaskUtil.run(() -> {
+ FairFight.getInstance().getServer().dispatchCommand(
+ FairFight.getInstance().getServer().getConsoleSender(),
+ FairFight.getInstance().getConfig().getString("ban-command").replaceAll("%player%", player.getName())
+ );
+ });
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/manager/PlayerDataManager.java b/src/main/java/me/joeleoli/fairfight/manager/PlayerDataManager.java
new file mode 100644
index 0000000..5fc231c
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/manager/PlayerDataManager.java
@@ -0,0 +1,31 @@
+package me.joeleoli.fairfight.manager;
+
+import me.joeleoli.fairfight.player.PlayerData;
+
+import org.bukkit.entity.Player;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+public class PlayerDataManager {
+
+ private final Map playerDataMap = new HashMap<>();
+
+ public void addPlayerData(Player player) {
+ this.playerDataMap.put(player.getUniqueId(), new PlayerData());
+ }
+
+ public void removePlayerData(Player player) {
+ this.playerDataMap.remove(player.getUniqueId());
+ }
+
+ public boolean hasPlayerData(Player player) {
+ return this.playerDataMap.containsKey(player.getUniqueId());
+ }
+
+ public PlayerData getPlayerData(Player player) {
+ return this.playerDataMap.get(player.getUniqueId());
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/mongo/FairFightLog.java b/src/main/java/me/joeleoli/fairfight/mongo/FairFightLog.java
new file mode 100644
index 0000000..1565349
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/mongo/FairFightLog.java
@@ -0,0 +1,24 @@
+package me.joeleoli.fairfight.mongo;
+
+import java.util.ArrayList;
+import java.util.List;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.UUID;
+
+@AllArgsConstructor
+@Getter
+public class FairFightLog {
+
+ @Getter
+ private static List queue = new ArrayList<>();
+
+ private UUID uuid;
+ private String flag;
+ private String client;
+ private int ping;
+ private double tps;
+ private long timestamp;
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/mongo/FairFightMongo.java b/src/main/java/me/joeleoli/fairfight/mongo/FairFightMongo.java
new file mode 100644
index 0000000..27ee849
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/mongo/FairFightMongo.java
@@ -0,0 +1,58 @@
+package me.joeleoli.fairfight.mongo;
+
+import com.mongodb.MongoClient;
+import com.mongodb.MongoCredential;
+import com.mongodb.ServerAddress;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.client.MongoDatabase;
+import java.util.Collections;
+import lombok.Getter;
+import me.joeleoli.fairfight.FairFight;
+
+import me.joeleoli.fairfight.util.nucleus.config.ConfigCursor;
+import org.bson.Document;
+
+@Getter
+public class FairFightMongo {
+
+ private MongoClient client;
+ private MongoDatabase database;
+ private MongoCollection logs;
+
+ public FairFightMongo() {
+ ConfigCursor cursor = new ConfigCursor(FairFight.getInstance().getMainFileConfig(), "mongo");
+
+ if (!cursor.exists("host")
+ || !cursor.exists("port")
+ || !cursor.exists("database")
+ || !cursor.exists("authentication.enabled")
+ || !cursor.exists("authentication.username")
+ || !cursor.exists("authentication.password")
+ || !cursor.exists("authentication.database")) {
+ throw new RuntimeException("Missing configuration option");
+ }
+
+ if (cursor.getBoolean("authentication.enabled")) {
+ final MongoCredential credential = MongoCredential.createCredential(
+ cursor.getString("authentication.username"),
+ cursor.getString("authentication.database"),
+ cursor.getString("authentication.password").toCharArray()
+ );
+
+ this.client = new MongoClient(
+ new ServerAddress(cursor.getString("host"), cursor.getInt("port")),
+ Collections.singletonList(credential)
+ );
+ } else {
+ this.client = new MongoClient(new ServerAddress(cursor.getString("host"), cursor.getInt("port")));
+ }
+
+ this.database = this.client.getDatabase("fairfight");
+ this.logs = this.database.getCollection("alert_logs");
+ }
+
+ public static FairFightMongo getInstance() {
+ return FairFight.getInstance().getMongo();
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/player/PlayerData.java b/src/main/java/me/joeleoli/fairfight/player/PlayerData.java
new file mode 100644
index 0000000..190b6a0
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/player/PlayerData.java
@@ -0,0 +1,268 @@
+package me.joeleoli.fairfight.player;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import me.joeleoli.fairfight.FairFight;
+import me.joeleoli.fairfight.check.impl.aimassist.*;
+import me.joeleoli.fairfight.check.impl.autoclicker.*;
+import me.joeleoli.fairfight.check.impl.badpackets.*;
+import me.joeleoli.fairfight.check.impl.inventory.*;
+import me.joeleoli.fairfight.check.impl.killaura.*;
+import me.joeleoli.fairfight.check.impl.velocity.VelocityA;
+import me.joeleoli.fairfight.check.ICheck;
+import me.joeleoli.fairfight.check.impl.fly.FlyA;
+import me.joeleoli.fairfight.check.impl.fly.FlyB;
+import me.joeleoli.fairfight.check.impl.fly.FlyC;
+import me.joeleoli.fairfight.check.impl.range.RangeA;
+import me.joeleoli.fairfight.check.impl.scaffold.ScaffoldA;
+import me.joeleoli.fairfight.check.impl.scaffold.ScaffoldB;
+import me.joeleoli.fairfight.check.impl.scaffold.ScaffoldC;
+import me.joeleoli.fairfight.check.impl.step.StepA;
+import me.joeleoli.fairfight.check.impl.timer.TimerA;
+import me.joeleoli.fairfight.check.impl.velocity.VelocityB;
+import me.joeleoli.fairfight.check.impl.velocity.VelocityC;
+import me.joeleoli.fairfight.check.impl.wtap.WTapA;
+import me.joeleoli.fairfight.check.impl.wtap.WTapB;
+import me.joeleoli.fairfight.client.ClientType;
+import me.joeleoli.fairfight.client.EnumClientType;
+import me.joeleoli.fairfight.util.CustomLocation;
+
+import net.minecraft.server.v1_8_R3.BlockPosition;
+
+import java.lang.reflect.Constructor;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Setter @Getter public final class PlayerData {
+
+ private static final Map, Constructor extends ICheck>> CONSTRUCTORS;
+ public static final Class extends ICheck>[] CHECKS;
+
+ private final Map> recentPlayerPackets;
+ private final Map> checkViolationTimes;
+ private final Map, ICheck> checkMap;
+ private final Map keepAliveTimes;
+ private final Map checkVlMap;
+ private final Set fakeBlocks = new HashSet<>();
+ private final Set teleportLocations;
+ private Map forgeMods;
+ private StringBuilder sniffedPacketBuilder;
+ private CustomLocation lastMovePacket;
+ private ClientType client;
+ private UUID lastTarget;
+ private String randomBanReason;
+ private double randomBanRate;
+ private boolean randomBan;
+ private boolean allowTeleport;
+ private boolean inventoryOpen;
+ private boolean setInventoryOpen;
+ private boolean sendingVape;
+ private boolean attackedSinceVelocity;
+ private boolean underBlock;
+ private boolean sprinting;
+ private boolean inLiquid;
+ private boolean instantBreakDigging;
+ private boolean fakeDigging;
+ private boolean onGround;
+ private boolean sniffing;
+ private boolean onStairs;
+ private boolean onCarpet;
+ private boolean placing;
+ private boolean banning;
+ private boolean digging;
+ private boolean inWeb;
+ private boolean onIce;
+ private boolean wasUnderBlock;
+ private boolean wasOnGround;
+ private boolean wasInLiquid;
+ private boolean wasInWeb;
+ private double lastGroundY;
+ private double velocityX;
+ private double velocityY;
+ private double velocityZ;
+ private long lastDelayedMovePacket;
+ private long lastAnimationPacket;
+ private long lastAttackPacket;
+ private long lastVelocity;
+ private long ping;
+ private int velocityH;
+ private int velocityV;
+ private int lastCps;
+ private int movementsSinceIce;
+ private int movementsSinceUnderBlock;
+
+ public PlayerData() {
+ this.recentPlayerPackets = new HashMap<>();
+ this.checkViolationTimes = new HashMap<>();
+ this.checkMap = new HashMap<>();
+ this.keepAliveTimes = new HashMap<>();
+ this.checkVlMap = new HashMap<>();
+ this.teleportLocations = Collections.newSetFromMap(new ConcurrentHashMap());
+ this.sniffedPacketBuilder = new StringBuilder();
+ this.client = EnumClientType.VANILLA;
+
+ FairFight.getInstance().getServer().getScheduler().runTaskAsynchronously(FairFight.getInstance(), () -> {
+ PlayerData.CONSTRUCTORS.keySet().stream().map(o -> (Class extends ICheck>) o).forEach(check -> {
+ Constructor extends ICheck> constructor = PlayerData.CONSTRUCTORS.get(check);
+ try {
+ this.checkMap.put(check, constructor.newInstance(this));
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ });
+ });
+ }
+
+ public T getCheck(final Class clazz) {
+ return (T) this.checkMap.get(clazz);
+ }
+
+ public CustomLocation getLastPlayerPacket(final UUID playerUUID, final int index) {
+ final List customLocations = this.recentPlayerPackets.get(playerUUID);
+ if (customLocations != null && customLocations.size() > index) {
+ return customLocations.get(customLocations.size() - index);
+ }
+ return null;
+ }
+
+ public void addPlayerPacket(final UUID playerUUID, final CustomLocation customLocation) {
+ List customLocations = this.recentPlayerPackets.get(playerUUID);
+ if (customLocations == null) {
+ customLocations = new ArrayList<>();
+ }
+ if (customLocations.size() == 20) {
+ customLocations.remove(0);
+ }
+ customLocations.add(customLocation);
+ this.recentPlayerPackets.put(playerUUID, customLocations);
+ }
+
+ public void addTeleportLocation(final CustomLocation teleportLocation) {
+ this.teleportLocations.add(teleportLocation);
+ }
+
+ public boolean allowTeleport(final CustomLocation teleportLocation) {
+ for (final CustomLocation customLocation : this.teleportLocations) {
+ final double delta = Math.pow(teleportLocation.getX() - customLocation.getX(), 2.0) +
+ Math.pow(teleportLocation.getZ() - customLocation.getZ(), 2.0);
+ if (delta <= 0.005) {
+ this.teleportLocations.remove(customLocation);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public double getCheckVl(final ICheck check) {
+ if (!this.checkVlMap.containsKey(check)) {
+ this.checkVlMap.put(check, 0.0);
+ }
+
+ return this.checkVlMap.get(check);
+ }
+
+ public void setCheckVl(double vl, final ICheck check) {
+ if (vl < 0.0) {
+ vl = 0.0;
+ }
+
+ this.checkVlMap.put(check, vl);
+ }
+
+ public boolean keepAliveExists(final int id) {
+ return this.keepAliveTimes.containsKey(id);
+ }
+
+ public long getKeepAliveTime(final int id) {
+ return this.keepAliveTimes.get(id);
+ }
+
+ public void removeKeepAliveTime(final int id) {
+ this.keepAliveTimes.remove(id);
+ }
+
+ public void addKeepAliveTime(final int id) {
+ this.keepAliveTimes.put(id, System.currentTimeMillis());
+ }
+
+ public int getViolations(final ICheck check, final Long time) {
+ final Set timestamps = this.checkViolationTimes.get(check);
+
+ if (timestamps != null) {
+ int violations = 0;
+
+ for (final long timestamp : timestamps) {
+ if (System.currentTimeMillis() - timestamp <= time) {
+ ++violations;
+ }
+ }
+
+ return violations;
+ }
+
+ return 0;
+ }
+
+ public void addViolation(final ICheck check) {
+ Set timestamps = this.checkViolationTimes.get(check);
+
+ if (timestamps == null) {
+ timestamps = new HashSet<>();
+ }
+
+ timestamps.add(System.currentTimeMillis());
+
+ this.checkViolationTimes.put(check, timestamps);
+ }
+
+ static {
+ CHECKS = new Class[]{
+ AimAssistA.class, AimAssistB.class, AimAssistC.class, AimAssistD.class,
+ AimAssistE.class,
+
+ AutoClickerA.class, AutoClickerB.class, AutoClickerC.class, AutoClickerD.class,
+ AutoClickerE.class, AutoClickerF.class, AutoClickerG.class, AutoClickerH.class,
+ AutoClickerI.class, AutoClickerJ.class, AutoClickerK.class, AutoClickerK.class,
+ AutoClickerL.class,
+
+ BadPacketsA.class, BadPacketsB.class, BadPacketsC.class, BadPacketsD.class,
+ BadPacketsE.class, BadPacketsF.class, BadPacketsG.class, BadPacketsH.class,
+ BadPacketsI.class, BadPacketsJ.class, BadPacketsK.class, BadPacketsL.class,
+
+ FlyA.class, FlyB.class, FlyC.class,
+
+ InventoryA.class, InventoryB.class, InventoryC.class, InventoryD.class,
+ InventoryE.class, InventoryF.class, InventoryG.class,
+
+ KillAuraA.class, KillAuraB.class, KillAuraC.class, KillAuraD.class,
+ KillAuraE.class, KillAuraF.class, KillAuraG.class, KillAuraH.class,
+ KillAuraI.class, KillAuraJ.class, KillAuraK.class, KillAuraL.class,
+ KillAuraM.class, KillAuraN.class, KillAuraO.class, KillAuraP.class,
+ KillAuraQ.class, KillAuraR.class, KillAuraS.class,
+
+ RangeA.class,
+
+ TimerA.class,
+
+ VelocityA.class, VelocityB.class, VelocityC.class,
+
+ WTapA.class, WTapB.class,
+
+ ScaffoldA.class, ScaffoldB.class, ScaffoldC.class,
+
+ StepA.class,
+ };
+
+ CONSTRUCTORS = new ConcurrentHashMap<>();
+
+ for (final Class extends ICheck> check : PlayerData.CHECKS) {
+ try {
+ PlayerData.CONSTRUCTORS.put(check, check.getConstructor(PlayerData.class));
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/task/InsertLogsTask.java b/src/main/java/me/joeleoli/fairfight/task/InsertLogsTask.java
new file mode 100644
index 0000000..c9594c7
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/task/InsertLogsTask.java
@@ -0,0 +1,40 @@
+package me.joeleoli.fairfight.task;
+
+import me.joeleoli.fairfight.mongo.FairFightLog;
+import me.joeleoli.fairfight.mongo.FairFightMongo;
+
+import org.bson.Document;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class InsertLogsTask implements Runnable {
+
+ @Override
+ public void run() {
+ final List documents = new ArrayList<>();
+ final Iterator iterator = FairFightLog.getQueue().iterator();
+
+ while (iterator.hasNext()) {
+ final FairFightLog log = iterator.next();
+ final Document document = new Document();
+
+ document.put("uuid", log.getUuid().toString());
+ document.put("flag", log.getFlag());
+ document.put("client", log.getClient());
+ document.put("ping", log.getPing());
+ document.put("tps", log.getTps());
+ document.put("timestamp", log.getTimestamp());
+
+ documents.add(document);
+
+ iterator.remove();
+ }
+
+ if (!documents.isEmpty()) {
+ FairFightMongo.getInstance().getLogs().insertMany(documents);
+ }
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/util/CustomLocation.java b/src/main/java/me/joeleoli/fairfight/util/CustomLocation.java
new file mode 100644
index 0000000..6691890
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/util/CustomLocation.java
@@ -0,0 +1,140 @@
+package me.joeleoli.fairfight.util;
+
+import java.util.StringJoiner;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.World;
+
+@Getter
+@Setter
+@AllArgsConstructor
+public class CustomLocation {
+
+ private final long timestamp = System.currentTimeMillis();
+
+ private String world;
+
+ private double x;
+ private double y;
+ private double z;
+
+ private float yaw;
+ private float pitch;
+
+ public CustomLocation(double x, double y, double z) {
+ this(x, y, z, 0.0F, 0.0F);
+ }
+
+ public CustomLocation(String world, double x, double y, double z) {
+ this(world, x, y, z, 0.0F, 0.0F);
+ }
+
+ public CustomLocation(double x, double y, double z, float yaw, float pitch) {
+ this("world", x, y, z, yaw, pitch);
+ }
+
+ public static CustomLocation fromBukkitLocation(Location location) {
+ return new CustomLocation(location.getWorld().getName(), location.getX(), location.getY(), location.getZ(),
+ location.getYaw(), location.getPitch());
+ }
+
+ public static CustomLocation stringToLocation(String string) {
+ String[] split = string.split(", ");
+
+ double x = Double.parseDouble(split[0]);
+ double y = Double.parseDouble(split[1]);
+ double z = Double.parseDouble(split[2]);
+
+ CustomLocation customLocation = new CustomLocation(x, y, z);
+
+ if (split.length == 4) {
+ customLocation.setWorld(split[3]);
+ } else if (split.length >= 5) {
+ customLocation.setYaw(Float.parseFloat(split[3]));
+ customLocation.setPitch(Float.parseFloat(split[4]));
+
+ if (split.length >= 6) {
+ customLocation.setWorld(split[5]);
+ }
+ }
+
+ return customLocation;
+ }
+
+ public static String locationToString(CustomLocation loc) {
+ StringJoiner joiner = new StringJoiner(", ");
+ joiner.add(Double.toString(loc.getX()));
+ joiner.add(Double.toString(loc.getY()));
+ joiner.add(Double.toString(loc.getZ()));
+
+ if (loc.getYaw() == 0.0f && loc.getPitch() == 0.0f) {
+ if (loc.getWorld().equals("world")) {
+ return joiner.toString();
+ } else {
+ joiner.add(loc.getWorld());
+ return joiner.toString();
+ }
+ } else {
+ joiner.add(Float.toString(loc.getYaw()));
+ joiner.add(Float.toString(loc.getPitch()));
+
+ if (loc.getWorld().equals("world")) {
+ return joiner.toString();
+ } else {
+ joiner.add(loc.getWorld());
+ return joiner.toString();
+ }
+ }
+ }
+
+ public Location toBukkitLocation() {
+ return new Location(this.toBukkitWorld(), this.x, this.y, this.z, this.yaw, this.pitch);
+ }
+
+ public double getGroundDistanceTo(CustomLocation location) {
+ return Math.sqrt(Math.pow(this.x - location.x, 2) + Math.pow(this.z - location.z, 2));
+ }
+
+ public double getDistanceTo(CustomLocation location) {
+ return Math.sqrt(Math.pow(this.x - location.x, 2) + Math.pow(this.y - location.y, 2) + Math.pow(this.z - location.z, 2));
+ }
+
+ public World toBukkitWorld() {
+ if (this.world == null) {
+ return Bukkit.getServer().getWorlds().get(0);
+ } else {
+ return Bukkit.getServer().getWorld(this.world);
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof CustomLocation)) {
+ return false;
+ }
+
+ CustomLocation location = (CustomLocation) obj;
+ return location.x == this.x && location.y == this.y && location.z == this.z
+ && location.pitch == this.pitch && location.yaw == this.yaw;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .append("x", this.x)
+ .append("y", this.y)
+ .append("z", this.z)
+ .append("yaw", this.yaw)
+ .append("pitch", this.pitch)
+ .append("world", this.world)
+ .append("timestamp", this.timestamp)
+ .toString();
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/util/MathUtil.java b/src/main/java/me/joeleoli/fairfight/util/MathUtil.java
new file mode 100644
index 0000000..36e97fa
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/util/MathUtil.java
@@ -0,0 +1,31 @@
+package me.joeleoli.fairfight.util;
+
+import net.minecraft.server.v1_8_R3.*;
+
+public class MathUtil {
+
+ public static float[] getRotationFromPosition(final CustomLocation playerLocation, final CustomLocation targetLocation) {
+ final double xDiff = targetLocation.getX() - playerLocation.getX();
+ final double zDiff = targetLocation.getZ() - playerLocation.getZ();
+ final double yDiff = targetLocation.getY() - (playerLocation.getY() + 0.12);
+ final double dist = MathHelper.sqrt(xDiff * xDiff + zDiff * zDiff);
+ final float yaw = (float)(Math.atan2(zDiff, xDiff) * 180.0 / 3.141592653589793) - 90.0f;
+ final float pitch = (float)(-(Math.atan2(yDiff, dist) * 180.0 / 3.141592653589793));
+ return new float[] { yaw, pitch };
+ }
+
+ public static int pingFormula(final long ping) {
+ return (int) Math.ceil(ping / 2L / 50.0) + 2;
+ }
+
+ public static float getDistanceBetweenAngles(final float angle1, final float angle2) {
+ float distance = Math.abs(angle1 - angle2) % 360.0f;
+
+ if (distance > 180.0f) {
+ distance = 360.0f - distance;
+ }
+
+ return distance;
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/util/nucleus/BlockUtil.java b/src/main/java/me/joeleoli/fairfight/util/nucleus/BlockUtil.java
new file mode 100644
index 0000000..2329a7a
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/util/nucleus/BlockUtil.java
@@ -0,0 +1,432 @@
+package me.joeleoli.fairfight.util.nucleus;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
+import org.bukkit.entity.Player;
+
+public class BlockUtil {
+
+ public static List blocked = new ArrayList<>();
+ private static Set blockSolidPassSet;
+ private static Set blockStairsSet;
+ private static Set blockLiquidsSet;
+ private static Set blockWebsSet;
+ private static Set blockIceSet;
+ private static Set blockCarpetSet;
+
+ static {
+ BlockUtil.blockSolidPassSet = new HashSet<>();
+ BlockUtil.blockStairsSet = new HashSet<>();
+ BlockUtil.blockLiquidsSet = new HashSet<>();
+ BlockUtil.blockWebsSet = new HashSet<>();
+ BlockUtil.blockIceSet = new HashSet<>();
+ BlockUtil.blockCarpetSet = new HashSet<>();
+ BlockUtil.blockSolidPassSet.add((byte) 0);
+ BlockUtil.blockSolidPassSet.add((byte) 6);
+ BlockUtil.blockSolidPassSet.add((byte) 8);
+ BlockUtil.blockSolidPassSet.add((byte) 9);
+ BlockUtil.blockSolidPassSet.add((byte) 10);
+ BlockUtil.blockSolidPassSet.add((byte) 11);
+ BlockUtil.blockSolidPassSet.add((byte) 27);
+ BlockUtil.blockSolidPassSet.add((byte) 28);
+ BlockUtil.blockSolidPassSet.add((byte) 30);
+ BlockUtil.blockSolidPassSet.add((byte) 31);
+ BlockUtil.blockSolidPassSet.add((byte) 32);
+ BlockUtil.blockSolidPassSet.add((byte) 37);
+ BlockUtil.blockSolidPassSet.add((byte) 38);
+ BlockUtil.blockSolidPassSet.add((byte) 39);
+ BlockUtil.blockSolidPassSet.add((byte) 40);
+ BlockUtil.blockSolidPassSet.add((byte) 50);
+ BlockUtil.blockSolidPassSet.add((byte) 51);
+ BlockUtil.blockSolidPassSet.add((byte) 55);
+ BlockUtil.blockSolidPassSet.add((byte) 59);
+ BlockUtil.blockSolidPassSet.add((byte) 63);
+ BlockUtil.blockSolidPassSet.add((byte) 66);
+ BlockUtil.blockSolidPassSet.add((byte) 68);
+ BlockUtil.blockSolidPassSet.add((byte) 69);
+ BlockUtil.blockSolidPassSet.add((byte) 70);
+ BlockUtil.blockSolidPassSet.add((byte) 72);
+ BlockUtil.blockSolidPassSet.add((byte) 75);
+ BlockUtil.blockSolidPassSet.add((byte) 76);
+ BlockUtil.blockSolidPassSet.add((byte) 77);
+ BlockUtil.blockSolidPassSet.add((byte) 78);
+ BlockUtil.blockSolidPassSet.add((byte) 83);
+ BlockUtil.blockSolidPassSet.add((byte) 90);
+ BlockUtil.blockSolidPassSet.add((byte) 104);
+ BlockUtil.blockSolidPassSet.add((byte) 105);
+ BlockUtil.blockSolidPassSet.add((byte) 115);
+ BlockUtil.blockSolidPassSet.add((byte) 119);
+ BlockUtil.blockSolidPassSet.add((byte) (-124));
+ BlockUtil.blockSolidPassSet.add((byte) (-113));
+ BlockUtil.blockSolidPassSet.add((byte) (-81));
+ BlockUtil.blockStairsSet.add((byte) 53);
+ BlockUtil.blockStairsSet.add((byte) 67);
+ BlockUtil.blockStairsSet.add((byte) 108);
+ BlockUtil.blockStairsSet.add((byte) 109);
+ BlockUtil.blockStairsSet.add((byte) 114);
+ BlockUtil.blockStairsSet.add((byte) (-128));
+ BlockUtil.blockStairsSet.add((byte) (-122));
+ BlockUtil.blockStairsSet.add((byte) (-121));
+ BlockUtil.blockStairsSet.add((byte) (-120));
+ BlockUtil.blockStairsSet.add((byte) (-100));
+ BlockUtil.blockStairsSet.add((byte) (-93));
+ BlockUtil.blockStairsSet.add((byte) (-92));
+ BlockUtil.blockStairsSet.add((byte) (-76));
+ BlockUtil.blockStairsSet.add((byte) 126);
+ BlockUtil.blockStairsSet.add((byte) (-74));
+ BlockUtil.blockStairsSet.add((byte) 44);
+ BlockUtil.blockStairsSet.add((byte) 78);
+ BlockUtil.blockStairsSet.add((byte) 99);
+ BlockUtil.blockStairsSet.add((byte) (-112));
+ BlockUtil.blockStairsSet.add((byte) (-115));
+ BlockUtil.blockStairsSet.add((byte) (-116));
+ BlockUtil.blockStairsSet.add((byte) (-105));
+ BlockUtil.blockStairsSet.add((byte) (-108));
+ BlockUtil.blockStairsSet.add((byte) 100);
+ BlockUtil.blockLiquidsSet.add((byte) 8);
+ BlockUtil.blockLiquidsSet.add((byte) 9);
+ BlockUtil.blockLiquidsSet.add((byte) 10);
+ BlockUtil.blockLiquidsSet.add((byte) 11);
+ BlockUtil.blockWebsSet.add((byte) 30);
+ BlockUtil.blockIceSet.add((byte) 79);
+ BlockUtil.blockIceSet.add((byte) (-82));
+ BlockUtil.blockCarpetSet.add((byte) (-85));
+
+ blocked.add(Material.ACTIVATOR_RAIL);
+ blocked.add(Material.ANVIL);
+ blocked.add(Material.BED_BLOCK);
+ blocked.add(Material.POTATO);
+ blocked.add(Material.POTATO_ITEM);
+ blocked.add(Material.CARROT);
+ blocked.add(Material.CARROT_ITEM);
+ blocked.add(Material.BIRCH_WOOD_STAIRS);
+ blocked.add(Material.BREWING_STAND);
+ blocked.add(Material.BOAT);
+ blocked.add(Material.BRICK_STAIRS);
+ blocked.add(Material.BROWN_MUSHROOM);
+ blocked.add(Material.CAKE_BLOCK);
+ blocked.add(Material.CARPET);
+ blocked.add(Material.CAULDRON);
+ blocked.add(Material.COBBLESTONE_STAIRS);
+ blocked.add(Material.COBBLE_WALL);
+ blocked.add(Material.DARK_OAK_STAIRS);
+ blocked.add(Material.DIODE);
+ blocked.add(Material.DIODE_BLOCK_ON);
+ blocked.add(Material.DIODE_BLOCK_OFF);
+ blocked.add(Material.DEAD_BUSH);
+ blocked.add(Material.DETECTOR_RAIL);
+ blocked.add(Material.DOUBLE_PLANT);
+ blocked.add(Material.DOUBLE_STEP);
+ blocked.add(Material.DRAGON_EGG);
+ blocked.add(Material.PAINTING);
+ blocked.add(Material.FLOWER_POT);
+ blocked.add(Material.GOLD_PLATE);
+ blocked.add(Material.HOPPER);
+ blocked.add(Material.STONE_PLATE);
+ blocked.add(Material.IRON_PLATE);
+ blocked.add(Material.HUGE_MUSHROOM_1);
+ blocked.add(Material.HUGE_MUSHROOM_2);
+ blocked.add(Material.IRON_DOOR_BLOCK);
+ blocked.add(Material.IRON_DOOR);
+ blocked.add(Material.FENCE);
+ blocked.add(Material.IRON_FENCE);
+ blocked.add(Material.IRON_PLATE);
+ blocked.add(Material.ITEM_FRAME);
+ blocked.add(Material.JUKEBOX);
+ blocked.add(Material.JUNGLE_WOOD_STAIRS);
+ blocked.add(Material.LADDER);
+ blocked.add(Material.LEVER);
+ blocked.add(Material.LONG_GRASS);
+ blocked.add(Material.NETHER_FENCE);
+ blocked.add(Material.NETHER_STALK);
+ blocked.add(Material.NETHER_WARTS);
+ blocked.add(Material.MELON_STEM);
+ blocked.add(Material.PUMPKIN_STEM);
+ blocked.add(Material.QUARTZ_STAIRS);
+ blocked.add(Material.RAILS);
+ blocked.add(Material.RED_MUSHROOM);
+ blocked.add(Material.RED_ROSE);
+ blocked.add(Material.SAPLING);
+ blocked.add(Material.SEEDS);
+ blocked.add(Material.SIGN);
+ blocked.add(Material.SIGN_POST);
+ blocked.add(Material.SKULL);
+ blocked.add(Material.SMOOTH_STAIRS);
+ blocked.add(Material.NETHER_BRICK_STAIRS);
+ blocked.add(Material.SPRUCE_WOOD_STAIRS);
+ blocked.add(Material.STAINED_GLASS_PANE);
+ blocked.add(Material.REDSTONE_COMPARATOR);
+ blocked.add(Material.REDSTONE_COMPARATOR_OFF);
+ blocked.add(Material.REDSTONE_COMPARATOR_ON);
+ blocked.add(Material.REDSTONE_LAMP_OFF);
+ blocked.add(Material.REDSTONE_LAMP_ON);
+ blocked.add(Material.REDSTONE_TORCH_OFF);
+ blocked.add(Material.REDSTONE_TORCH_ON);
+ blocked.add(Material.REDSTONE_WIRE);
+ blocked.add(Material.SANDSTONE_STAIRS);
+ blocked.add(Material.STEP);
+ blocked.add(Material.ACACIA_STAIRS);
+ blocked.add(Material.SUGAR_CANE);
+ blocked.add(Material.SUGAR_CANE_BLOCK);
+ blocked.add(Material.ENCHANTMENT_TABLE);
+ blocked.add(Material.SOUL_SAND);
+ blocked.add(Material.TORCH);
+ blocked.add(Material.TRAP_DOOR);
+ blocked.add(Material.TRIPWIRE);
+ blocked.add(Material.TRIPWIRE_HOOK);
+ blocked.add(Material.WALL_SIGN);
+ blocked.add(Material.VINE);
+ blocked.add(Material.WATER_LILY);
+ blocked.add(Material.WEB);
+ blocked.add(Material.WOOD_DOOR);
+ blocked.add(Material.WOOD_DOUBLE_STEP);
+ blocked.add(Material.WOOD_PLATE);
+ blocked.add(Material.WOOD_STAIRS);
+ blocked.add(Material.WOOD_STEP);
+ blocked.add(Material.HOPPER);
+ blocked.add(Material.WOODEN_DOOR);
+ blocked.add(Material.YELLOW_FLOWER);
+ blocked.add(Material.LAVA);
+ blocked.add(Material.WATER);
+ blocked.add(Material.STATIONARY_WATER);
+ blocked.add(Material.STATIONARY_LAVA);
+ blocked.add(Material.CACTUS);
+ blocked.add(Material.CHEST);
+ blocked.add(Material.PISTON_BASE);
+ blocked.add(Material.PISTON_MOVING_PIECE);
+ blocked.add(Material.PISTON_EXTENSION);
+ blocked.add(Material.PISTON_STICKY_BASE);
+ blocked.add(Material.TRAPPED_CHEST);
+ blocked.add(Material.SNOW);
+ blocked.add(Material.ENDER_CHEST);
+ blocked.add(Material.THIN_GLASS);
+ blocked.add(Material.ENDER_PORTAL_FRAME);
+ }
+
+ public static boolean isOnStairs(final Location location, final int down) {
+ return isUnderBlock(location, BlockUtil.blockStairsSet, down);
+ }
+
+ public static boolean isOnLiquid(final Location location, final int down) {
+ return isUnderBlock(location, BlockUtil.blockLiquidsSet, down);
+ }
+
+ public static boolean isOnWeb(final Location location, final int down) {
+ return isUnderBlock(location, BlockUtil.blockWebsSet, down);
+ }
+
+ public static boolean isOnIce(final Location location, final int down) {
+ return isUnderBlock(location, BlockUtil.blockIceSet, down);
+ }
+
+ public static boolean isOnCarpet(final Location location, final int down) {
+ return isUnderBlock(location, BlockUtil.blockCarpetSet, down);
+ }
+
+ public static boolean isSlab(final Player player) {
+ return blocked.contains(player.getLocation().getBlock().getRelative(BlockFace.DOWN).getType());
+ }
+
+ public static boolean isBlockFaceAir(final Player player) {
+ final Block block = player.getLocation().getBlock().getRelative(BlockFace.DOWN);
+ return block.getType().equals(Material.AIR) && block.getRelative(BlockFace.WEST).getType().equals(Material
+ .AIR) && block.getRelative(BlockFace.NORTH).getType().equals(Material.AIR) && block.getRelative
+ (BlockFace.EAST).getType().equals(Material.AIR) && block.getRelative(BlockFace.SOUTH).getType()
+ .equals(Material.AIR);
+ }
+
+ private static boolean isUnderBlock(final Location location, final Set itemIDs, final int down) {
+ final double posX = location.getX();
+ final double posZ = location.getZ();
+ final double fracX = (posX % 1.0 > 0.0) ? Math.abs(posX % 1.0) : (1.0 - Math.abs(posX % 1.0));
+ final double fracZ = (posZ % 1.0 > 0.0) ? Math.abs(posZ % 1.0) : (1.0 - Math.abs(posZ % 1.0));
+ final int blockX = location.getBlockX();
+ final int blockY = location.getBlockY() - down;
+ final int blockZ = location.getBlockZ();
+ final World world = location.getWorld();
+
+ if (itemIDs.contains((byte) world.getBlockAt(blockX, blockY, blockZ).getTypeId())) {
+ return true;
+ }
+
+ if (fracX < 0.3) {
+ if (itemIDs.contains((byte) world.getBlockAt(blockX - 1, blockY, blockZ).getTypeId())) {
+ return true;
+ }
+
+ if (fracZ < 0.3) {
+ if (itemIDs.contains((byte) world.getBlockAt(blockX - 1, blockY, blockZ - 1).getTypeId())) {
+ return true;
+ }
+
+ if (itemIDs.contains((byte) world.getBlockAt(blockX, blockY, blockZ - 1).getTypeId())) {
+ return true;
+ }
+
+ if (itemIDs.contains((byte) world.getBlockAt(blockX + 1, blockY, blockZ - 1).getTypeId())) {
+ return true;
+ }
+ } else if (fracZ > 0.7) {
+ if (itemIDs.contains((byte) world.getBlockAt(blockX - 1, blockY, blockZ + 1).getTypeId())) {
+ return true;
+ }
+
+ if (itemIDs.contains((byte) world.getBlockAt(blockX, blockY, blockZ + 1).getTypeId())) {
+ return true;
+ }
+
+ if (itemIDs.contains((byte) world.getBlockAt(blockX + 1, blockY, blockZ + 1).getTypeId())) {
+ return true;
+ }
+ }
+ } else if (fracX > 0.7) {
+ if (itemIDs.contains((byte) world.getBlockAt(blockX + 1, blockY, blockZ).getTypeId())) {
+ return true;
+ }
+
+ if (fracZ < 0.3) {
+ if (itemIDs.contains((byte) world.getBlockAt(blockX - 1, blockY, blockZ - 1).getTypeId())) {
+ return true;
+ }
+
+ if (itemIDs.contains((byte) world.getBlockAt(blockX, blockY, blockZ - 1).getTypeId())) {
+ return true;
+ }
+
+ if (itemIDs.contains((byte) world.getBlockAt(blockX + 1, blockY, blockZ - 1).getTypeId())) {
+ return true;
+ }
+ } else if (fracZ > 0.7) {
+ if (itemIDs.contains((byte) world.getBlockAt(blockX - 1, blockY, blockZ + 1).getTypeId())) {
+ return true;
+ }
+
+ if (itemIDs.contains((byte) world.getBlockAt(blockX, blockY, blockZ + 1).getTypeId())) {
+ return true;
+ }
+
+ if (itemIDs.contains((byte) world.getBlockAt(blockX + 1, blockY, blockZ + 1).getTypeId())) {
+ return true;
+ }
+ }
+ } else if (fracZ < 0.3) {
+ if (itemIDs.contains((byte) world.getBlockAt(blockX, blockY, blockZ - 1).getTypeId())) {
+ return true;
+ }
+ } else if (fracZ > 0.7 && itemIDs.contains((byte) world.getBlockAt(blockX, blockY, blockZ + 1).getTypeId())) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public static boolean isOnGround(final Location location, final int down) {
+ final double posX = location.getX();
+ final double posZ = location.getZ();
+ final double fracX = (posX % 1.0 > 0.0) ? Math.abs(posX % 1.0) : (1.0 - Math.abs(posX % 1.0));
+ final double fracZ = (posZ % 1.0 > 0.0) ? Math.abs(posZ % 1.0) : (1.0 - Math.abs(posZ % 1.0));
+ final int blockX = location.getBlockX();
+ final int blockY = location.getBlockY() - down;
+ final int blockZ = location.getBlockZ();
+ final World world = location.getWorld();
+
+ if (!BlockUtil.blockSolidPassSet.contains((byte) world.getBlockAt(blockX, blockY, blockZ).getTypeId())) {
+ return true;
+ }
+
+ if (fracX < 0.3) {
+ if (!BlockUtil.blockSolidPassSet.contains((byte) world.getBlockAt(blockX - 1, blockY, blockZ).getTypeId()
+ )) {
+ return true;
+ }
+
+ if (fracZ < 0.3) {
+ if (!BlockUtil.blockSolidPassSet.contains((byte) world.getBlockAt(blockX - 1, blockY, blockZ - 1)
+ .getTypeId())) {
+ return true;
+ }
+
+ if (!BlockUtil.blockSolidPassSet.contains((byte) world.getBlockAt(blockX, blockY, blockZ - 1)
+ .getTypeId())) {
+ return true;
+ }
+
+ if (!BlockUtil.blockSolidPassSet.contains((byte) world.getBlockAt(blockX + 1, blockY, blockZ - 1)
+ .getTypeId())) {
+ return true;
+ }
+ } else if (fracZ > 0.7) {
+ if (!BlockUtil.blockSolidPassSet.contains((byte) world.getBlockAt(blockX - 1, blockY, blockZ + 1)
+ .getTypeId())) {
+ return true;
+ }
+
+ if (!BlockUtil.blockSolidPassSet.contains((byte) world.getBlockAt(blockX, blockY, blockZ + 1)
+ .getTypeId())) {
+ return true;
+ }
+
+ if (!BlockUtil.blockSolidPassSet.contains((byte) world.getBlockAt(blockX + 1, blockY, blockZ + 1)
+ .getTypeId())) {
+ return true;
+ }
+ }
+ } else if (fracX > 0.7) {
+ if (!BlockUtil.blockSolidPassSet.contains((byte) world.getBlockAt(blockX + 1, blockY, blockZ).getTypeId()
+ )) {
+ return true;
+ }
+
+ if (fracZ < 0.3) {
+ if (!BlockUtil.blockSolidPassSet.contains((byte) world.getBlockAt(blockX - 1, blockY, blockZ - 1)
+ .getTypeId())) {
+ return true;
+ }
+
+ if (!BlockUtil.blockSolidPassSet.contains((byte) world.getBlockAt(blockX, blockY, blockZ - 1)
+ .getTypeId())) {
+ return true;
+ }
+
+ if (!BlockUtil.blockSolidPassSet.contains((byte) world.getBlockAt(blockX + 1, blockY, blockZ - 1)
+ .getTypeId())) {
+ return true;
+ }
+ } else if (fracZ > 0.7) {
+ if (!BlockUtil.blockSolidPassSet.contains((byte) world.getBlockAt(blockX - 1, blockY, blockZ + 1)
+ .getTypeId())) {
+ return true;
+ }
+
+ if (!BlockUtil.blockSolidPassSet.contains((byte) world.getBlockAt(blockX, blockY, blockZ + 1)
+ .getTypeId())) {
+ return true;
+ }
+
+ if (!BlockUtil.blockSolidPassSet.contains((byte) world.getBlockAt(blockX + 1, blockY, blockZ + 1)
+ .getTypeId())) {
+ return true;
+ }
+ }
+ } else if (fracZ < 0.3) {
+ if (!BlockUtil.blockSolidPassSet.contains((byte) world.getBlockAt(blockX, blockY, blockZ - 1).getTypeId()
+ )) {
+ return true;
+ }
+ } else if (fracZ > 0.7 && !BlockUtil.blockSolidPassSet.contains((byte) world.getBlockAt(blockX, blockY,
+ blockZ + 1
+ ).getTypeId())) {
+ return true;
+ }
+
+ return false;
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/util/nucleus/config/ConfigCursor.java b/src/main/java/me/joeleoli/fairfight/util/nucleus/config/ConfigCursor.java
new file mode 100644
index 0000000..c8baea3
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/util/nucleus/config/ConfigCursor.java
@@ -0,0 +1,76 @@
+package me.joeleoli.fairfight.util.nucleus.config;
+
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+import org.bukkit.Bukkit;
+import org.bukkit.World;
+
+@AllArgsConstructor
+@Getter
+public class ConfigCursor {
+
+ private final FileConfig fileConfig;
+ @Setter private String path;
+
+ public boolean exists() {
+ return this.exists(null);
+ }
+
+ public boolean exists(String path) {
+ return this.fileConfig.getConfig().contains(this.path + (path == null ? "" : "." + path));
+ }
+
+ public Set getKeys() {
+ return this.getKeys(null);
+ }
+
+ public Set getKeys(String path) {
+ return this.fileConfig.getConfig().getConfigurationSection(this.path + (path == null ? "" : "." + path))
+ .getKeys(false);
+ }
+
+ public String getString(String path) {
+ return this.fileConfig.getConfig().getString((this.path == null ? "" : this.path + ".") + path);
+ }
+
+ public boolean getBoolean(String path) {
+ return this.fileConfig.getConfig().getBoolean((this.path == null ? "" : this.path + ".") + "." + path);
+ }
+
+ public int getInt(String path) {
+ return this.fileConfig.getConfig().getInt((this.path == null ? "" : this.path + ".") + "." + path);
+ }
+
+ public long getLong(String path) {
+ return this.fileConfig.getConfig().getLong((this.path == null ? "" : this.path + ".") + "." + path);
+ }
+
+ public List getStringList(String path) {
+ return this.fileConfig.getConfig().getStringList((this.path == null ? "" : this.path + ".") + "." + path);
+ }
+
+ public UUID getUuid(String path) {
+ return UUID.fromString(this.fileConfig.getConfig().getString(this.path + "." + path));
+ }
+
+ public World getWorld(String path) {
+ return Bukkit.getWorld(this.fileConfig.getConfig().getString(this.path + "." + path));
+ }
+
+ public void set(Object value) {
+ this.set(null, value);
+ }
+
+ public void set(String path, Object value) {
+ this.fileConfig.getConfig().set(this.path + (path == null ? "" : "." + path), value);
+ }
+
+ public void save() {
+ this.fileConfig.save();
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/util/nucleus/config/FileConfig.java b/src/main/java/me/joeleoli/fairfight/util/nucleus/config/FileConfig.java
new file mode 100644
index 0000000..d566785
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/util/nucleus/config/FileConfig.java
@@ -0,0 +1,46 @@
+package me.joeleoli.fairfight.util.nucleus.config;
+
+import java.io.File;
+import java.io.IOException;
+import lombok.Getter;
+import org.bukkit.Bukkit;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.plugin.java.JavaPlugin;
+
+@Getter
+public class FileConfig {
+
+ private File file;
+ private FileConfiguration config;
+
+ public FileConfig(JavaPlugin plugin, String fileName) {
+ this.file = new File(plugin.getDataFolder(), fileName);
+
+ if (!this.file.exists()) {
+ this.file.getParentFile().mkdirs();
+
+ if (plugin.getResource(fileName) == null) {
+ try {
+ this.file.createNewFile();
+ } catch (IOException e) {
+ plugin.getLogger().severe("Failed to create new file " + fileName);
+ }
+ } else {
+ plugin.saveResource(fileName, false);
+ }
+ }
+
+ this.config = YamlConfiguration.loadConfiguration(this.file);
+ }
+
+ public void save() {
+ try {
+ this.config.save(this.file);
+ } catch (IOException e) {
+ Bukkit.getLogger().severe("Could not save config file " + this.file.toString());
+ e.printStackTrace();
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/me/joeleoli/fairfight/util/nucleus/listener/ListenerHandler.java b/src/main/java/me/joeleoli/fairfight/util/nucleus/listener/ListenerHandler.java
new file mode 100644
index 0000000..96be835
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/util/nucleus/listener/ListenerHandler.java
@@ -0,0 +1,45 @@
+package me.joeleoli.fairfight.util.nucleus.listener;
+
+import me.joeleoli.fairfight.util.nucleus.util.ClassUtil;
+import org.bukkit.event.Listener;
+import org.bukkit.plugin.Plugin;
+
+public class ListenerHandler {
+
+ /**
+ * Registers all listeners from the given package with the given plugin.
+ *
+ * @param plugin The plugin responsible for these listeners. This is here because the .getClassesInPackage
+ * method requires it (for no real reason)
+ * @param packageName The package to load listeners from. Example: "me.joeleoli.nucleus.listeners"
+ */
+ public static void loadListenersFromPackage(Plugin plugin, String packageName) {
+ for (Class> clazz : ClassUtil.getClassesInPackage(plugin, packageName)) {
+ if (isListener(clazz)) {
+ try {
+ plugin.getServer().getPluginManager().registerEvents((Listener) clazz.newInstance(), plugin);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ * Check if the given class implements the {@link Listener} interface.
+ *
+ * @param clazz The class to check
+ *
+ * @return If the class implements the {@link Listener} interface
+ */
+ public static boolean isListener(Class> clazz) {
+ for (Class> interfaze : clazz.getInterfaces()) {
+ if (interfaze == Listener.class) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/util/nucleus/util/ClassUtil.java b/src/main/java/me/joeleoli/fairfight/util/nucleus/util/ClassUtil.java
new file mode 100644
index 0000000..13533f0
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/util/nucleus/util/ClassUtil.java
@@ -0,0 +1,80 @@
+package me.joeleoli.fairfight.util.nucleus.util;
+
+import com.google.common.collect.ImmutableSet;
+import java.io.IOException;
+import java.net.URL;
+import java.security.CodeSource;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import org.bukkit.plugin.Plugin;
+
+public final class ClassUtil {
+
+ private ClassUtil() {
+ throw new RuntimeException("Cannot instantiate a utility class.");
+ }
+
+ /**
+ * Gets all the classes in a the provided package.
+ *
+ * @param plugin The plugin who owns the package
+ * @param packageName The package to scan classes in.
+ *
+ * @return The classes in the package packageName.
+ */
+ public static Collection> getClassesInPackage(Plugin plugin, String packageName) {
+ Collection> classes = new ArrayList<>();
+
+ CodeSource codeSource = plugin.getClass().getProtectionDomain().getCodeSource();
+ URL resource = codeSource.getLocation();
+ String relPath = packageName.replace('.', '/');
+ String resPath = resource.getPath().replace("%20", " ");
+ String jarPath = resPath.replaceFirst("[.]jar[!].*", ".jar").replaceFirst("file:", "");
+ JarFile jarFile;
+
+ try {
+ jarFile = new JarFile(jarPath);
+ } catch (IOException e) {
+ throw (new RuntimeException("Unexpected IOException reading JAR File '" + jarPath + "'", e));
+ }
+
+ Enumeration entries = jarFile.entries();
+
+ while (entries.hasMoreElements()) {
+ JarEntry entry = entries.nextElement();
+ String entryName = entry.getName();
+ String className = null;
+
+ if (entryName.endsWith(".class") && entryName.startsWith(relPath) &&
+ entryName.length() > (relPath.length() + "/".length())) {
+ className = entryName.replace('/', '.').replace('\\', '.').replace(".class", "");
+ }
+
+ if (className != null) {
+ Class> clazz = null;
+
+ try {
+ clazz = Class.forName(className);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+
+ if (clazz != null) {
+ classes.add(clazz);
+ }
+ }
+ }
+
+ try {
+ jarFile.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return (ImmutableSet.copyOf(classes));
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/me/joeleoli/fairfight/util/nucleus/util/ItemUtil.java b/src/main/java/me/joeleoli/fairfight/util/nucleus/util/ItemUtil.java
new file mode 100644
index 0000000..4d5a9e8
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/util/nucleus/util/ItemUtil.java
@@ -0,0 +1,196 @@
+package me.joeleoli.fairfight.util.nucleus.util;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import me.joeleoli.fairfight.FairFight;
+import me.joeleoli.fairfight.util.zoot.util.BukkitReflection;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.WordUtils;
+import org.bukkit.Material;
+import org.bukkit.inventory.ItemStack;
+
+public class ItemUtil {
+
+ private static final Map NAME_MAP = new HashMap<>();
+
+ public static ItemData[] repeat(Material material, int times) {
+ return repeat(material, (byte) 0, times);
+ }
+
+ public static ItemData[] repeat(Material material, byte data, int times) {
+ ItemData[] itemData = new ItemData[times];
+
+ for (int i = 0; i < times; i++) {
+ itemData[i] = new ItemData(material, data);
+ }
+
+ return itemData;
+
+ }
+
+ public static ItemData[] armorOf(ArmorPart part) {
+ List data = new ArrayList<>();
+
+ for (ArmorType at : ArmorType.values()) {
+ data.add(new ItemData(Material.valueOf(at.name() + "_" + part.name()), (short) 0));
+ }
+
+ return data.toArray(new ItemData[data.size()]);
+ }
+
+ public static ItemData[] swords() {
+ List data = new ArrayList<>();
+
+ for (SwordType at : SwordType.values()) {
+ data.add(new ItemData(Material.valueOf(at.name() + "_SWORD"), (short) 0));
+ }
+
+ return data.toArray(new ItemData[data.size()]);
+ }
+
+ public static void load() {
+ NAME_MAP.clear();
+
+ List lines = readLines();
+
+ for (String line : lines) {
+ String[] parts = line.split(",");
+
+ NAME_MAP.put(
+ parts[0],
+ new ItemData(Material.getMaterial(Integer.parseInt(parts[1])), Short.parseShort(parts[2]))
+ );
+ }
+ }
+
+ public static ItemStack get(String input, int amount) {
+ ItemStack item = get(input);
+
+ if (item != null) {
+ item.setAmount(amount);
+ }
+
+ return item;
+ }
+
+ public static ItemStack get(String input) {
+ if (NumberUtil.isInteger(input)) {
+ return new ItemStack(Material.getMaterial(Integer.parseInt(input)));
+ }
+
+ if (input.contains(":")) {
+ if (NumberUtil.isShort(input.split(":")[1])) {
+ if (NumberUtil.isInteger(input.split(":")[0])) {
+ return new ItemStack(
+ Material.getMaterial(Integer.parseInt(input.split(":")[0])), 1,
+ Short.parseShort(input.split(":")[1])
+ );
+ } else {
+ if (!NAME_MAP.containsKey(input.split(":")[0].toLowerCase())) {
+ return null;
+ }
+
+ ItemData data = NAME_MAP.get(input.split(":")[0].toLowerCase());
+ return new ItemStack(data.getMaterial(), 1, Short.parseShort(input.split(":")[1]));
+ }
+ } else {
+ return null;
+ }
+ }
+
+ if (!NAME_MAP.containsKey(input)) {
+ return null;
+ }
+
+ return NAME_MAP.get(input).toItemStack();
+ }
+
+ public static String getName(ItemStack item) {
+ if (item.getDurability() != 0) {
+ String reflectedName = BukkitReflection.getItemStackName(item);
+
+ if (reflectedName != null) {
+ if (reflectedName.contains(".")) {
+ reflectedName = WordUtils.capitalize(item.getType().toString().toLowerCase().replace("_", " "));
+ }
+
+ return reflectedName;
+ }
+ }
+
+ String string = item.getType().toString().replace("_", " ");
+ char[] chars = string.toLowerCase().toCharArray();
+ boolean found = false;
+
+ for (int i = 0; i < chars.length; i++) {
+ if (!found && Character.isLetter(chars[i])) {
+ chars[i] = Character.toUpperCase(chars[i]);
+ found = true;
+ } else if (Character.isWhitespace(chars[i]) || chars[i] == '.' || chars[i] == '\'') {
+ found = false;
+ }
+ }
+
+ return String.valueOf(chars);
+ }
+
+ private static List readLines() {
+ try {
+ return IOUtils.readLines(FairFight.class.getClassLoader().getResourceAsStream("items.csv"));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+
+ public enum ArmorPart {
+ HELMET,
+ CHESTPLATE,
+ LEGGINGS,
+ BOOTS
+ }
+
+ public enum ArmorType {
+ DIAMOND,
+ IRON,
+ GOLD,
+ LEATHER
+ }
+
+ public enum SwordType {
+ DIAMOND,
+ IRON,
+ GOLD,
+ STONE
+ }
+
+ @Getter
+ @AllArgsConstructor
+ public static class ItemData {
+
+ private final Material material;
+ private final short data;
+
+ public String getName() {
+ return ItemUtil.getName(toItemStack());
+ }
+
+ public boolean matches(ItemStack item) {
+ return item != null && item.getType() == material && item.getDurability() == data;
+ }
+
+ public ItemStack toItemStack() {
+ return new ItemStack(material, 1, data);
+ }
+
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/util/nucleus/util/NumberUtil.java b/src/main/java/me/joeleoli/fairfight/util/nucleus/util/NumberUtil.java
new file mode 100644
index 0000000..7ab4e79
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/util/nucleus/util/NumberUtil.java
@@ -0,0 +1,80 @@
+package me.joeleoli.fairfight.util.nucleus.util;
+
+import java.text.NumberFormat;
+import java.util.Locale;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.TreeMap;
+import java.util.concurrent.ThreadLocalRandom;
+
+public class NumberUtil {
+
+ private static final NavigableMap SUFFIXES = new TreeMap<>();
+
+ static {
+ SUFFIXES.put(1_000L, "k");
+ SUFFIXES.put(1_000_000L, "M");
+ SUFFIXES.put(1_000_000_000L, "B");
+ SUFFIXES.put(1_000_000_000_000L, "T");
+ SUFFIXES.put(1_000_000_000_000L, "Q");
+ SUFFIXES.put(1_000_000_000_000_000L, "QT");
+ }
+
+ public static int getRandomRange(int min, int max) {
+ return ThreadLocalRandom.current().nextInt(min, max + 1);
+ }
+
+ public static float getRandomRange() {
+ return ThreadLocalRandom.current().nextFloat();
+ }
+
+ public static boolean isInteger(String input) {
+ try {
+ Integer.parseInt(input);
+ return true;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+
+ public static boolean isShort(String input) {
+ try {
+ Short.parseShort(input);
+ return true;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+
+ public static boolean isEven(int number) {
+ return number % 2 == 0;
+ }
+
+ public static String convertAbbreviated(long value) {
+ if (value == Long.MIN_VALUE) {
+ return convertAbbreviated(Long.MIN_VALUE + 1);
+ }
+
+ if (value < 0) {
+ return "-" + convertAbbreviated(-value);
+ }
+
+ if (value < 1000) {
+ return Long.toString(value);
+ }
+
+ Map.Entry e = SUFFIXES.floorEntry(value);
+ Long divideBy = e.getKey();
+ String suffix = e.getValue();
+
+ long truncated = value / (divideBy / 10);
+ boolean hasDecimal = truncated < 100 && (truncated / 10d) != (truncated / 10);
+
+ return hasDecimal ? (truncated / 10d) + suffix : (truncated / 10) + suffix;
+ }
+
+ public static String formatNumber(long value) {
+ return NumberFormat.getInstance(Locale.US).format(value);
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/util/nucleus/util/TaskUtil.java b/src/main/java/me/joeleoli/fairfight/util/nucleus/util/TaskUtil.java
new file mode 100644
index 0000000..39d9ee9
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/util/nucleus/util/TaskUtil.java
@@ -0,0 +1,29 @@
+package me.joeleoli.fairfight.util.nucleus.util;
+
+
+import me.joeleoli.fairfight.FairFight;
+import org.bukkit.scheduler.BukkitRunnable;
+
+public class TaskUtil {
+
+ public static void run(Runnable runnable) {
+ FairFight.getInstance().getServer().getScheduler().runTask(FairFight.getInstance(), runnable);
+ }
+
+ public static void runTimer(Runnable runnable, long delay, long timer) {
+ FairFight.getInstance().getServer().getScheduler().runTaskTimer(FairFight.getInstance(), runnable, delay, timer);
+ }
+
+ public static void runTimer(BukkitRunnable runnable, long delay, long timer) {
+ runnable.runTaskTimer(FairFight.getInstance(), delay, timer);
+ }
+
+ public static void runLater(Runnable runnable, long delay) {
+ FairFight.getInstance().getServer().getScheduler().runTaskLater(FairFight.getInstance(), runnable, delay);
+ }
+
+ public static void runAsync(Runnable runnable) {
+ FairFight.getInstance().getServer().getScheduler().runTaskAsynchronously(FairFight.getInstance(), runnable);
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/util/update/MovementUpdate.java b/src/main/java/me/joeleoli/fairfight/util/update/MovementUpdate.java
new file mode 100644
index 0000000..8847d2e
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/util/update/MovementUpdate.java
@@ -0,0 +1,25 @@
+package me.joeleoli.fairfight.util.update;
+
+import lombok.Getter;
+
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+
+import org.bukkit.Location;
+import org.bukkit.entity.Player;
+
+@Getter
+public class MovementUpdate {
+
+ private Player player;
+ private Location to;
+ private Location from;
+ private PacketPlayInFlying packet;
+
+ public MovementUpdate(final Player player, final Location to, final Location from, final PacketPlayInFlying packet) {
+ this.player = player;
+ this.to = to;
+ this.from = from;
+ this.packet = packet;
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/util/update/PositionUpdate.java b/src/main/java/me/joeleoli/fairfight/util/update/PositionUpdate.java
new file mode 100644
index 0000000..5f95118
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/util/update/PositionUpdate.java
@@ -0,0 +1,14 @@
+package me.joeleoli.fairfight.util.update;
+
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+
+import org.bukkit.Location;
+import org.bukkit.entity.Player;
+
+public class PositionUpdate extends MovementUpdate {
+
+ public PositionUpdate(Player player, Location to, Location from, PacketPlayInFlying packet) {
+ super(player, to, from, packet);
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/util/update/RotationUpdate.java b/src/main/java/me/joeleoli/fairfight/util/update/RotationUpdate.java
new file mode 100644
index 0000000..66c8a5c
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/util/update/RotationUpdate.java
@@ -0,0 +1,14 @@
+package me.joeleoli.fairfight.util.update;
+
+import net.minecraft.server.v1_8_R3.PacketPlayInFlying;
+
+import org.bukkit.Location;
+import org.bukkit.entity.Player;
+
+public class RotationUpdate extends MovementUpdate {
+
+ public RotationUpdate(Player player, Location to, Location from, PacketPlayInFlying packet) {
+ super(player, to, from, packet);
+ }
+
+}
diff --git a/src/main/java/me/joeleoli/fairfight/util/zoot/util/BukkitReflection.java b/src/main/java/me/joeleoli/fairfight/util/zoot/util/BukkitReflection.java
new file mode 100644
index 0000000..1f127d8
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/util/zoot/util/BukkitReflection.java
@@ -0,0 +1,94 @@
+package me.joeleoli.fairfight.util.zoot.util;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Server;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+public class BukkitReflection
+{
+ private static String CRAFT_BUKKIT_PACKAGE;
+ private static String NET_MINECRAFT_SERVER_PACKAGE;
+ private static Class CRAFT_SERVER_CLASS;
+ private static Method CRAFT_SERVER_GET_HANDLE_METHOD;
+ private static Class PLAYER_LIST_CLASS;
+ private static Field PLAYER_LIST_MAX_PLAYERS_FIELD;
+ private static Class CRAFT_PLAYER_CLASS;
+ private static Method CRAFT_PLAYER_GET_HANDLE_METHOD;
+ private static Class ENTITY_PLAYER_CLASS;
+ private static Field ENTITY_PLAYER_PING_FIELD;
+ private static Class CRAFT_ITEM_STACK_CLASS;
+ private static Method CRAFT_ITEM_STACK_AS_NMS_COPY_METHOD;
+ private static Class ENTITY_ITEM_STACK_CLASS;
+ private static Method ENTITY_ITEM_STACK_GET_NAME;
+ private static Class SPIGOT_CONFIG_CLASS;
+ private static Field SPIGOT_CONFIG_BUNGEE_FIELD;
+
+ public static int getPing(Player player) {
+ try {
+ int ping = BukkitReflection.ENTITY_PLAYER_PING_FIELD.getInt(BukkitReflection.CRAFT_PLAYER_GET_HANDLE_METHOD.invoke(player, new Object[0]));
+ return (ping > 0) ? ping : 0;
+ }
+ catch (Exception e) {
+ return 1;
+ }
+ }
+
+ public static void setMaxPlayers(Server server, int slots) {
+ try {
+ BukkitReflection.PLAYER_LIST_MAX_PLAYERS_FIELD.set(BukkitReflection.CRAFT_SERVER_GET_HANDLE_METHOD.invoke(server, new Object[0]), slots);
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static String getItemStackName(ItemStack itemStack) {
+ try {
+ return (String)BukkitReflection.ENTITY_ITEM_STACK_GET_NAME.invoke(BukkitReflection.CRAFT_ITEM_STACK_AS_NMS_COPY_METHOD.invoke(itemStack, itemStack), new Object[0]);
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ return "";
+ }
+ }
+
+ public static boolean isBungeeServer() {
+ try {
+ return (boolean)BukkitReflection.SPIGOT_CONFIG_BUNGEE_FIELD.get(null);
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ static {
+ try {
+ String version = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3];
+ CRAFT_BUKKIT_PACKAGE = "org.bukkit.craftbukkit." + version + ".";
+ NET_MINECRAFT_SERVER_PACKAGE = "net.minecraft.server." + version + ".";
+ CRAFT_SERVER_CLASS = Class.forName(BukkitReflection.CRAFT_BUKKIT_PACKAGE + "CraftServer");
+ (CRAFT_SERVER_GET_HANDLE_METHOD = BukkitReflection.CRAFT_SERVER_CLASS.getDeclaredMethod("getHandle", (Class[])new Class[0])).setAccessible(true);
+ PLAYER_LIST_CLASS = Class.forName(BukkitReflection.NET_MINECRAFT_SERVER_PACKAGE + "PlayerList");
+ (PLAYER_LIST_MAX_PLAYERS_FIELD = BukkitReflection.PLAYER_LIST_CLASS.getDeclaredField("maxPlayers")).setAccessible(true);
+ CRAFT_PLAYER_CLASS = Class.forName(BukkitReflection.CRAFT_BUKKIT_PACKAGE + "entity.CraftPlayer");
+ (CRAFT_PLAYER_GET_HANDLE_METHOD = BukkitReflection.CRAFT_PLAYER_CLASS.getDeclaredMethod("getHandle", (Class[])new Class[0])).setAccessible(true);
+ ENTITY_PLAYER_CLASS = Class.forName(BukkitReflection.NET_MINECRAFT_SERVER_PACKAGE + "EntityPlayer");
+ (ENTITY_PLAYER_PING_FIELD = BukkitReflection.ENTITY_PLAYER_CLASS.getDeclaredField("ping")).setAccessible(true);
+ CRAFT_ITEM_STACK_CLASS = Class.forName(BukkitReflection.CRAFT_BUKKIT_PACKAGE + "inventory.CraftItemStack");
+ (CRAFT_ITEM_STACK_AS_NMS_COPY_METHOD = BukkitReflection.CRAFT_ITEM_STACK_CLASS.getDeclaredMethod("asNMSCopy", ItemStack.class)).setAccessible(true);
+ ENTITY_ITEM_STACK_CLASS = Class.forName(BukkitReflection.NET_MINECRAFT_SERVER_PACKAGE + "ItemStack");
+ ENTITY_ITEM_STACK_GET_NAME = BukkitReflection.ENTITY_ITEM_STACK_CLASS.getDeclaredMethod("getName", (Class[])new Class[0]);
+ SPIGOT_CONFIG_CLASS = Class.forName("org.spigotmc.SpigotConfig");
+ (SPIGOT_CONFIG_BUNGEE_FIELD = BukkitReflection.SPIGOT_CONFIG_CLASS.getDeclaredField("bungee")).setAccessible(true);
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Failed to initialize Bukkit/NMS Reflection");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/joeleoli/fairfight/util/zoot/util/CC.java b/src/main/java/me/joeleoli/fairfight/util/zoot/util/CC.java
new file mode 100644
index 0000000..9f6a069
--- /dev/null
+++ b/src/main/java/me/joeleoli/fairfight/util/zoot/util/CC.java
@@ -0,0 +1,85 @@
+package me.joeleoli.fairfight.util.zoot.util;
+
+import org.bukkit.ChatColor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CC
+{
+ public static final String BLUE;
+ public static final String AQUA;
+ public static final String YELLOW;
+ public static final String RED;
+ public static final String GRAY;
+ public static final String GOLD;
+ public static final String GREEN;
+ public static final String WHITE;
+ public static final String BLACK;
+ public static final String BOLD;
+ public static final String ITALIC;
+ public static final String UNDER_LINE;
+ public static final String STRIKE_THROUGH;
+ public static final String RESET;
+ public static final String MAGIC;
+ public static final String DARK_BLUE;
+ public static final String DARK_AQUA;
+ public static final String DARK_GRAY;
+ public static final String DARK_GREEN;
+ public static final String DARK_PURPLE;
+ public static final String DARK_RED;
+ public static final String PINK;
+ public static final String MENU_BAR;
+ public static final String CHAT_BAR;
+ public static final String SB_BAR;
+
+ public static String translate(String in) {
+ return ChatColor.translateAlternateColorCodes('&', in);
+ }
+
+ public static List translate(List lines) {
+ List toReturn = new ArrayList<>();
+ for (String line : lines) {
+ toReturn.add(ChatColor.translateAlternateColorCodes('&', line));
+ }
+ return toReturn;
+ }
+
+ public static List translate(String[] lines) {
+ List toReturn = new ArrayList<>();
+ for (String line : lines) {
+ if (line != null) {
+ toReturn.add(ChatColor.translateAlternateColorCodes('&', line));
+ }
+ }
+ return toReturn;
+ }
+
+ static {
+ BLUE = ChatColor.BLUE.toString();
+ AQUA = ChatColor.AQUA.toString();
+ YELLOW = ChatColor.YELLOW.toString();
+ RED = ChatColor.RED.toString();
+ GRAY = ChatColor.GRAY.toString();
+ GOLD = ChatColor.GOLD.toString();
+ GREEN = ChatColor.GREEN.toString();
+ WHITE = ChatColor.WHITE.toString();
+ BLACK = ChatColor.BLACK.toString();
+ BOLD = ChatColor.BOLD.toString();
+ ITALIC = ChatColor.ITALIC.toString();
+ UNDER_LINE = ChatColor.UNDERLINE.toString();
+ STRIKE_THROUGH = ChatColor.STRIKETHROUGH.toString();
+ RESET = ChatColor.RESET.toString();
+ MAGIC = ChatColor.MAGIC.toString();
+ DARK_BLUE = ChatColor.DARK_BLUE.toString();
+ DARK_AQUA = ChatColor.DARK_AQUA.toString();
+ DARK_GRAY = ChatColor.DARK_GRAY.toString();
+ DARK_GREEN = ChatColor.DARK_GREEN.toString();
+ DARK_PURPLE = ChatColor.DARK_PURPLE.toString();
+ DARK_RED = ChatColor.DARK_RED.toString();
+ PINK = ChatColor.LIGHT_PURPLE.toString();
+ MENU_BAR = ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH.toString() + "------------------------";
+ CHAT_BAR = ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH.toString() + "------------------------------------------------";
+ SB_BAR = ChatColor.GRAY.toString() + ChatColor.STRIKETHROUGH.toString() + "----------------------";
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
new file mode 100644
index 0000000..58dc4ed
--- /dev/null
+++ b/src/main/resources/config.yml
@@ -0,0 +1,19 @@
+# Placeholders: %player%
+name: "&8[&6FairFight&8]"
+ban-broadcast:
+- '&8&m-------------------------------------'
+- ''
+- '&6FairFight &7has removed &e%player%'
+- '&7From the &eMineXD Network.'
+- ''
+- '&8&m-------------------------------------'
+ban-command: "ban %player% FairFight - Unfair Advantage"
+mongo:
+ host: "127.0.0.1"
+ port: 27017
+ database: "fairfight"
+ authentication:
+ enabled: false
+ username: "admin"
+ password: "dev"
+ database: "admin"
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
new file mode 100644
index 0000000..ce33b2f
--- /dev/null
+++ b/src/main/resources/plugin.yml
@@ -0,0 +1,8 @@
+name: FairFight
+author: joeleoli
+version: 1.0
+main: me.joeleoli.fairfight.FairFight
+commands:
+ fairfight:
+ usage:
+ aliases: [ff]
\ No newline at end of file