commit 9e6219006d67404fdb9905f4efcb7a6cec8f6341 Author: ObamaRuntz Date: Wed Sep 11 16:14:08 2024 +0100 sponsored by the evil jews diff --git a/libs/CrackShot.jar b/libs/CrackShot.jar new file mode 100644 index 0000000..6861bb5 Binary files /dev/null and b/libs/CrackShot.jar differ diff --git a/libs/DiscordBotAPI-1.1.0.jar b/libs/DiscordBotAPI-1.1.0.jar new file mode 100644 index 0000000..d682b00 Binary files /dev/null and b/libs/DiscordBotAPI-1.1.0.jar differ diff --git a/libs/GSit-1.2.2.jar b/libs/GSit-1.2.2.jar new file mode 100644 index 0000000..b7100e3 Binary files /dev/null and b/libs/GSit-1.2.2.jar differ diff --git a/libs/mcMMO.jar b/libs/mcMMO.jar new file mode 100644 index 0000000..222db24 Binary files /dev/null and b/libs/mcMMO.jar differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..1cbc2ed --- /dev/null +++ b/pom.xml @@ -0,0 +1,169 @@ + + + 4.0.0 + + me.frep + Vulcan + 2.6.7-HOTFIX + + + 1.8 + UTF-8 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + ${java.version} + ${java.version} + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.4 + + + package + + shade + + + false + Vulcant + + + + + + + + src/main/resources + true + + + + + + + spigotmc-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + jitpack.io + https://jitpack.io + + + placeholderapi + https://repo.extendedclip.com/content/repositories/placeholderapi/ + + + codemc-snapshots + https://repo.codemc.io/repository/maven-snapshots/ + + + opencollab-snapshot-repo + https://repo.opencollab.dev/maven-snapshots/ + + + lumine-repo + https://mvn.lumine.io/repository/maven-public/ + + + + + net.wesjd + anvilgui + 1.5.3-SNAPSHOT + compile + + + org.geysermc + core + 2.0.0-SNAPSHOT + provided + + + io.lumine.xikage + MythicMobs + LATEST + provided + + + com.github.DieReicheErethons + Brewery + 3.1.1 + provided + + + org.geysermc.floodgate + api + 2.2.0-SNAPSHOT + provided + + + org.spigotmc + spigot-api + 1.18.2-R0.1-SNAPSHOT + provided + + + me.clip + placeholderapi + 2.11.1 + provided + + + org.jetbrains + annotations + 16.0.2 + compile + + + com.github.retrooper + packetevents + 3b947e7b9a + compile + + + org.projectlombok + lombok + 1.18.22 + provided + + + nigger1 + niggaballs + 1.0 + system + /home/isnow/Desktop/Development/vulcant/libs/CrackShot.jar + + + nigger12 + niggaballs + 1.0 + system + /home/isnow/Desktop/Development/vulcant/libs/GSit-1.2.2.jar + + + nigger3 + niggaballs + 1.0 + system + /home/isnow/Desktop/Development/vulcant/libs/mcMMO.jar + + + nigger4 + niggaballs + 1.0 + system + /home/isnow/Desktop/Development/vulcant/libs/DiscordBotAPI-1.1.0.jar + + + \ No newline at end of file diff --git a/src/main/java/me/frep/vulcan/api/VulcanAPI.java b/src/main/java/me/frep/vulcan/api/VulcanAPI.java new file mode 100644 index 0000000..7b5fbdf --- /dev/null +++ b/src/main/java/me/frep/vulcan/api/VulcanAPI.java @@ -0,0 +1,119 @@ +package me.frep.vulcan.api; + +import javax.annotation.Nullable; +import java.util.Set; +import java.util.List; +import me.frep.vulcan.api.check.Check; +import me.frep.vulcan.api.check.ICheckData; +import java.util.Map; +import me.frep.vulcan.api.data.IPlayerData; +import org.bukkit.entity.Player; + +public interface VulcanAPI +{ + void toggleAlerts(final Player p0); + + void toggleVerbose(final Player p0); + + IPlayerData getPlayerData(final Player p0); + + int getPing(final Player p0); + + double getKurtosis(final Player p0); + + int getTransactionPing(final Player p0); + + int getSensitivity(final Player p0); + + void executeBanWave(); + + void setFrozen(final Player p0, final boolean p1); + + double getCps(final Player p0); + + int getTotalViolations(final Player p0); + + boolean isFrozen(final Player p0); + + int getMovementViolations(final Player p0); + + int getPlayerViolations(final Player p0); + + int getCombatViolations(final Player p0); + + double getTps(); + + String getServerVersion(); + + Map getCheckData(); + + int getJoinTicks(final Player p0); + + String getClientVersion(final Player p0); + + boolean hasAlertsEnabled(final Player p0); + + Check getCheck(final Player p0, final String p1, final char p2); + + String getVulcanVersion(); + + boolean isCheckEnabled(final String p0); + + int getTicks(); + + List getChecks(final Player p0); + + Map getEnabledChecks(); + + Map getMaxViolations(); + + Map getAlertIntervals(); + + Map getMinimumViolationsToNotify(); + + Map> getPunishmentCommands(); + + Map getPunishableChecks(); + + Map getBroadcastPunishments(); + + Map getMaximumPings(); + + Map getMinimumTps(); + + Map getMaxBuffers(); + + Map getBufferDecays(); + + Map getBufferMultiples(); + + Map getHotbarShuffle(); + + Map getHotbarShuffleMinimums(); + + Map getHotbarShuffleIntervals(); + + Map getRandomRotation(); + + Map getRandomRotationMinimums(); + + Map getRandomRotationIntervals(); + + Set getChecks(); + + void flag(final Player p0, final String p1, final String p2, final String p3); + + public static class Factory + { + private static VulcanAPI api; + + @Nullable + public static VulcanAPI getApi() { + return Factory.api; + } + + public static void setApi(final VulcanAPI api) { + Factory.api = api; + } + } +} diff --git a/src/main/java/me/frep/vulcan/api/check/Check.java b/src/main/java/me/frep/vulcan/api/check/Check.java new file mode 100644 index 0000000..61edda6 --- /dev/null +++ b/src/main/java/me/frep/vulcan/api/check/Check.java @@ -0,0 +1,42 @@ +package me.frep.vulcan.api.check; + +public interface Check +{ + String getCategory(); + + String getName(); + + char getType(); + + char getDisplayType(); + + int getMaxVl(); + + int getVl(); + + double getMaxBuffer(); + + boolean isExperimental(); + + double getBufferDecay(); + + double getBufferMultiple(); + + int getMinimumVlToNotify(); + + int getAlertInterval(); + + double getBuffer(); + + void setVl(final int p0); + + boolean isPunishable(); + + void setBuffer(final double p0); + + String getDescription(); + + String getComplexType(); + + String getDisplayName(); +} diff --git a/src/main/java/me/frep/vulcan/api/check/ICheckData.java b/src/main/java/me/frep/vulcan/api/check/ICheckData.java new file mode 100644 index 0000000..08965f3 --- /dev/null +++ b/src/main/java/me/frep/vulcan/api/check/ICheckData.java @@ -0,0 +1,40 @@ +package me.frep.vulcan.api.check; + +import java.util.List; + +public interface ICheckData +{ + boolean isEnabled(); + + boolean isPunishable(); + + boolean isBroadcastPunishment(); + + boolean isHotbarShuffle(); + + boolean isRandomRotation(); + + int getMaxViolations(); + + int getAlertInterval(); + + int getMinimumVlToNotify(); + + int getMaxPing(); + + int getMinimumVlToRandomlyRotate(); + + int getMinimumVlToShuffleHotbar(); + + double getMinimumTps(); + + double getMaxBuffer(); + + double getBufferDecay(); + + double getBufferMultiple(); + + List getPunishmentCommands(); + + int getRandomRotationInterval(); +} diff --git a/src/main/java/me/frep/vulcan/api/data/IPlayerData.java b/src/main/java/me/frep/vulcan/api/data/IPlayerData.java new file mode 100644 index 0000000..02b7f05 --- /dev/null +++ b/src/main/java/me/frep/vulcan/api/data/IPlayerData.java @@ -0,0 +1,26 @@ +package me.frep.vulcan.api.data; + +public interface IPlayerData +{ + int getTotalViolations(); + + int getCombatViolations(); + + int getMovementViolations(); + + int getPlayerViolations(); + + int getAutoClickerViolations(); + + int getTimerViolations(); + + int getScaffoldViolations(); + + long getJoinTime(); + + int getJoinTicks(); + + String getClientBrand(); + + long getLastClientBrandAlert(); +} diff --git a/src/main/java/me/frep/vulcan/api/event/VulcanDisableAlertsEvent.java b/src/main/java/me/frep/vulcan/api/event/VulcanDisableAlertsEvent.java new file mode 100644 index 0000000..b5ba7f1 --- /dev/null +++ b/src/main/java/me/frep/vulcan/api/event/VulcanDisableAlertsEvent.java @@ -0,0 +1,47 @@ +package me.frep.vulcan.api.event; + +import org.bukkit.event.HandlerList; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; + +public class VulcanDisableAlertsEvent extends Event implements Cancellable +{ + private boolean cancelled; + private final Player player; + private final long timestamp; + private static final HandlerList handlers; + + public VulcanDisableAlertsEvent(final Player player) { + this.timestamp = System.currentTimeMillis(); + this.player = player; + } + + public HandlerList getHandlers() { + return VulcanDisableAlertsEvent.handlers; + } + + public static HandlerList getHandlerList() { + return VulcanDisableAlertsEvent.handlers; + } + + public boolean isCancelled() { + return this.cancelled; + } + + public Player getPlayer() { + return this.player; + } + + public long getTimestamp() { + return this.timestamp; + } + + public void setCancelled(final boolean cancelled) { + this.cancelled = cancelled; + } + + static { + handlers = new HandlerList(); + } +} diff --git a/src/main/java/me/frep/vulcan/api/event/VulcanEnableAlertsEvent.java b/src/main/java/me/frep/vulcan/api/event/VulcanEnableAlertsEvent.java new file mode 100644 index 0000000..73215eb --- /dev/null +++ b/src/main/java/me/frep/vulcan/api/event/VulcanEnableAlertsEvent.java @@ -0,0 +1,47 @@ +package me.frep.vulcan.api.event; + +import org.bukkit.event.HandlerList; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; + +public class VulcanEnableAlertsEvent extends Event implements Cancellable +{ + private boolean cancelled; + private final Player player; + private final long timestamp; + private static final HandlerList handlers; + + public VulcanEnableAlertsEvent(final Player player) { + this.timestamp = System.currentTimeMillis(); + this.player = player; + } + + public HandlerList getHandlers() { + return VulcanEnableAlertsEvent.handlers; + } + + public static HandlerList getHandlerList() { + return VulcanEnableAlertsEvent.handlers; + } + + public boolean isCancelled() { + return this.cancelled; + } + + public Player getPlayer() { + return this.player; + } + + public long getTimestamp() { + return this.timestamp; + } + + public void setCancelled(final boolean cancelled) { + this.cancelled = cancelled; + } + + static { + handlers = new HandlerList(); + } +} diff --git a/src/main/java/me/frep/vulcan/api/event/VulcanFlagEvent.java b/src/main/java/me/frep/vulcan/api/event/VulcanFlagEvent.java new file mode 100644 index 0000000..ed2092d --- /dev/null +++ b/src/main/java/me/frep/vulcan/api/event/VulcanFlagEvent.java @@ -0,0 +1,61 @@ +package me.frep.vulcan.api.event; + +import org.bukkit.event.HandlerList; +import me.frep.vulcan.api.check.Check; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; + +public class VulcanFlagEvent extends Event implements Cancellable +{ + private boolean cancelled; + private final Player player; + private final Check check; + private final String info; + private final long timestamp; + private static final HandlerList handlers; + + public VulcanFlagEvent(final Player player, final Check check, final String info) { + super(true); + this.timestamp = System.currentTimeMillis(); + this.player = player; + this.check = check; + this.info = info; + } + + public HandlerList getHandlers() { + return VulcanFlagEvent.handlers; + } + + public static HandlerList getHandlerList() { + return VulcanFlagEvent.handlers; + } + + public boolean isCancelled() { + return this.cancelled; + } + + public void setCancelled(final boolean cancel) { + this.cancelled = cancel; + } + + public Player getPlayer() { + return this.player; + } + + public Check getCheck() { + return this.check; + } + + public String getInfo() { + return this.info; + } + + public long getTimestamp() { + return this.timestamp; + } + + static { + handlers = new HandlerList(); + } +} diff --git a/src/main/java/me/frep/vulcan/api/event/VulcanGhostBlockEvent.java b/src/main/java/me/frep/vulcan/api/event/VulcanGhostBlockEvent.java new file mode 100644 index 0000000..6a77373 --- /dev/null +++ b/src/main/java/me/frep/vulcan/api/event/VulcanGhostBlockEvent.java @@ -0,0 +1,48 @@ +package me.frep.vulcan.api.event; + +import org.bukkit.event.HandlerList; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; + +public class VulcanGhostBlockEvent extends Event implements Cancellable +{ + private final Player player; + private boolean cancelled; + private final long timestamp; + private static final HandlerList handlers; + + public VulcanGhostBlockEvent(final Player player) { + super(true); + this.timestamp = System.currentTimeMillis(); + this.player = player; + } + + public HandlerList getHandlers() { + return VulcanGhostBlockEvent.handlers; + } + + public static HandlerList getHandlerList() { + return VulcanGhostBlockEvent.handlers; + } + + public boolean isCancelled() { + return this.cancelled; + } + + public void setCancelled(final boolean cancel) { + this.cancelled = cancel; + } + + public Player getPlayer() { + return this.player; + } + + public long getTimestamp() { + return this.timestamp; + } + + static { + handlers = new HandlerList(); + } +} diff --git a/src/main/java/me/frep/vulcan/api/event/VulcanJudgementDayEndEvent.java b/src/main/java/me/frep/vulcan/api/event/VulcanJudgementDayEndEvent.java new file mode 100644 index 0000000..6fab02d --- /dev/null +++ b/src/main/java/me/frep/vulcan/api/event/VulcanJudgementDayEndEvent.java @@ -0,0 +1,35 @@ +package me.frep.vulcan.api.event; + +import org.bukkit.event.HandlerList; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; + +public class VulcanJudgementDayEndEvent extends Event implements Cancellable +{ + private boolean cancelled; + private static final HandlerList handlers; + + public VulcanJudgementDayEndEvent() { + super(true); + } + + public HandlerList getHandlers() { + return VulcanJudgementDayEndEvent.handlers; + } + + public static HandlerList getHandlerList() { + return VulcanJudgementDayEndEvent.handlers; + } + + public boolean isCancelled() { + return this.cancelled; + } + + public void setCancelled(final boolean cancel) { + this.cancelled = cancel; + } + + static { + handlers = new HandlerList(); + } +} diff --git a/src/main/java/me/frep/vulcan/api/event/VulcanJudgementDayStartEvent.java b/src/main/java/me/frep/vulcan/api/event/VulcanJudgementDayStartEvent.java new file mode 100644 index 0000000..48e6960 --- /dev/null +++ b/src/main/java/me/frep/vulcan/api/event/VulcanJudgementDayStartEvent.java @@ -0,0 +1,35 @@ +package me.frep.vulcan.api.event; + +import org.bukkit.event.HandlerList; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; + +public class VulcanJudgementDayStartEvent extends Event implements Cancellable +{ + private boolean cancelled; + private static final HandlerList handlers; + + public VulcanJudgementDayStartEvent() { + super(true); + } + + public HandlerList getHandlers() { + return VulcanJudgementDayStartEvent.handlers; + } + + public static HandlerList getHandlerList() { + return VulcanJudgementDayStartEvent.handlers; + } + + public boolean isCancelled() { + return this.cancelled; + } + + public void setCancelled(final boolean cancel) { + this.cancelled = cancel; + } + + static { + handlers = new HandlerList(); + } +} diff --git a/src/main/java/me/frep/vulcan/api/event/VulcanPostFlagEvent.java b/src/main/java/me/frep/vulcan/api/event/VulcanPostFlagEvent.java new file mode 100644 index 0000000..7f52793 --- /dev/null +++ b/src/main/java/me/frep/vulcan/api/event/VulcanPostFlagEvent.java @@ -0,0 +1,61 @@ +package me.frep.vulcan.api.event; + +import org.bukkit.event.HandlerList; +import me.frep.vulcan.api.check.Check; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; + +public class VulcanPostFlagEvent extends Event implements Cancellable +{ + private boolean cancelled; + private final Player player; + private final Check check; + private final String info; + private final long timestamp; + private static final HandlerList handlers; + + public VulcanPostFlagEvent(final Player player, final Check check, final String info) { + super(true); + this.timestamp = System.currentTimeMillis(); + this.player = player; + this.check = check; + this.info = info; + } + + public HandlerList getHandlers() { + return VulcanPostFlagEvent.handlers; + } + + public static HandlerList getHandlerList() { + return VulcanPostFlagEvent.handlers; + } + + public boolean isCancelled() { + return this.cancelled; + } + + public void setCancelled(final boolean cancel) { + this.cancelled = cancel; + } + + public Player getPlayer() { + return this.player; + } + + public Check getCheck() { + return this.check; + } + + public String getInfo() { + return this.info; + } + + public long getTimestamp() { + return this.timestamp; + } + + static { + handlers = new HandlerList(); + } +} diff --git a/src/main/java/me/frep/vulcan/api/event/VulcanPunishEvent.java b/src/main/java/me/frep/vulcan/api/event/VulcanPunishEvent.java new file mode 100644 index 0000000..74bb15b --- /dev/null +++ b/src/main/java/me/frep/vulcan/api/event/VulcanPunishEvent.java @@ -0,0 +1,49 @@ +package me.frep.vulcan.api.event; + +import org.bukkit.event.HandlerList; +import me.frep.vulcan.api.check.Check; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; + +public class VulcanPunishEvent extends Event implements Cancellable +{ + private boolean cancelled; + private final Player player; + private final Check check; + private static final HandlerList handlers; + + public VulcanPunishEvent(final Player player, final Check check) { + super(true); + this.player = player; + this.check = check; + } + + public HandlerList getHandlers() { + return VulcanPunishEvent.handlers; + } + + public static HandlerList getHandlerList() { + return VulcanPunishEvent.handlers; + } + + public boolean isCancelled() { + return this.cancelled; + } + + public void setCancelled(final boolean cancel) { + this.cancelled = cancel; + } + + public Player getPlayer() { + return this.player; + } + + public Check getCheck() { + return this.check; + } + + static { + handlers = new HandlerList(); + } +} diff --git a/src/main/java/me/frep/vulcan/api/event/VulcanRegisterPlayerEvent.java b/src/main/java/me/frep/vulcan/api/event/VulcanRegisterPlayerEvent.java new file mode 100644 index 0000000..5d357b7 --- /dev/null +++ b/src/main/java/me/frep/vulcan/api/event/VulcanRegisterPlayerEvent.java @@ -0,0 +1,42 @@ +package me.frep.vulcan.api.event; + +import org.bukkit.event.HandlerList; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; + +public class VulcanRegisterPlayerEvent extends Event implements Cancellable +{ + private boolean cancelled; + private final Player player; + private static final HandlerList handlers; + + public VulcanRegisterPlayerEvent(final Player player) { + super(true); + this.player = player; + } + + public HandlerList getHandlers() { + return VulcanRegisterPlayerEvent.handlers; + } + + public static HandlerList getHandlerList() { + return VulcanRegisterPlayerEvent.handlers; + } + + public boolean isCancelled() { + return this.cancelled; + } + + public Player getPlayer() { + return this.player; + } + + public void setCancelled(final boolean cancelled) { + this.cancelled = cancelled; + } + + static { + handlers = new HandlerList(); + } +} diff --git a/src/main/java/me/frep/vulcan/api/event/VulcanSetbackEvent.java b/src/main/java/me/frep/vulcan/api/event/VulcanSetbackEvent.java new file mode 100644 index 0000000..6ee4525 --- /dev/null +++ b/src/main/java/me/frep/vulcan/api/event/VulcanSetbackEvent.java @@ -0,0 +1,55 @@ +package me.frep.vulcan.api.event; + +import org.bukkit.event.HandlerList; +import me.frep.vulcan.api.check.Check; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; + +public class VulcanSetbackEvent extends Event implements Cancellable +{ + private final Player player; + private boolean cancelled; + private final Check check; + private final long timestamp; + private static final HandlerList handlers; + + public VulcanSetbackEvent(final Player player, final Check check) { + super(true); + this.timestamp = System.currentTimeMillis(); + this.player = player; + this.check = check; + } + + public HandlerList getHandlers() { + return VulcanSetbackEvent.handlers; + } + + public static HandlerList getHandlerList() { + return VulcanSetbackEvent.handlers; + } + + public boolean isCancelled() { + return this.cancelled; + } + + public void setCancelled(final boolean cancel) { + this.cancelled = cancel; + } + + public Player getPlayer() { + return this.player; + } + + public Check getCheck() { + return this.check; + } + + public long getTimestamp() { + return this.timestamp; + } + + static { + handlers = new HandlerList(); + } +} diff --git a/src/main/java/me/frep/vulcan/api/event/VulcanViolationResetEvent.java b/src/main/java/me/frep/vulcan/api/event/VulcanViolationResetEvent.java new file mode 100644 index 0000000..d24379d --- /dev/null +++ b/src/main/java/me/frep/vulcan/api/event/VulcanViolationResetEvent.java @@ -0,0 +1,31 @@ +package me.frep.vulcan.api.event; + +import org.bukkit.event.HandlerList; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; + +public class VulcanViolationResetEvent extends Event implements Cancellable +{ + private boolean cancelled; + private static final HandlerList handlers; + + public HandlerList getHandlers() { + return VulcanViolationResetEvent.handlers; + } + + public static HandlerList getHandlerList() { + return VulcanViolationResetEvent.handlers; + } + + public boolean isCancelled() { + return this.cancelled; + } + + public void setCancelled(final boolean cancelled) { + this.cancelled = cancelled; + } + + static { + handlers = new HandlerList(); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/Vulcan.java b/src/main/java/me/frep/vulcan/spigot/Vulcan.java new file mode 100644 index 0000000..d1fa4ad --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/Vulcan.java @@ -0,0 +1,439 @@ +package me.frep.vulcan.spigot; + +import java.util.Objects; +import java.util.logging.Level; +import me.frep.vulcan.spigot.util.CacheUtil; +import me.frep.vulcan.spigot.hook.placeholderapi.PlaceholderAPIExtension; +import io.github.retrooper.packetevents.event.PacketListenerAbstract; +import me.frep.vulcan.spigot.network.NetworkManager; +import io.github.retrooper.packetevents.event.priority.PacketEventPriority; +import io.github.retrooper.packetevents.PacketEvents; +import me.frep.vulcan.spigot.event.EventProcessor1_13; +import me.frep.vulcan.spigot.event.EventProcessor1_11; +import me.frep.vulcan.spigot.hook.brewery.BreweryHook; +import me.frep.vulcan.spigot.hook.gsit.GSitListener; +import me.frep.vulcan.spigot.hook.mythicmobs.MythicMobsHook; +import me.frep.vulcan.spigot.hook.crackshot.CrackShotHook; +import me.frep.vulcan.spigot.hook.mcmmo.McMMOHook; +import me.frep.vulcan.spigot.event.EventProcessor; +import org.bukkit.event.Listener; +import me.frep.vulcan.spigot.listener.PlayerListener; +import org.bukkit.plugin.messaging.PluginMessageListener; +import me.frep.vulcan.spigot.brand.ClientBrandListener; +import me.frep.vulcan.spigot.bukkit.Metrics; +import org.bukkit.plugin.Plugin; +import me.frep.vulcan.spigot.command.impl.LogsCommand; +import me.frep.vulcan.spigot.command.impl.JDayCommand; +import org.bukkit.command.TabCompleter; +import me.frep.vulcan.spigot.command.tab.VulcanTabCompleter; +import me.frep.vulcan.spigot.command.impl.VulcanCommand; +import me.frep.vulcan.spigot.command.impl.AlertsCommand; +import me.frep.vulcan.spigot.command.impl.VerboseCommand; +import org.bukkit.command.CommandExecutor; +import me.frep.vulcan.spigot.command.impl.PunishLogs; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.check.manager.CheckManager; +import me.frep.vulcan.spigot.config.Stats; +import me.frep.vulcan.spigot.config.Config; +import java.util.concurrent.Executors; +import java.util.HashMap; +import org.bukkit.Bukkit; +import me.frep.vulcan.spigot.id.ID; +import me.frep.vulcan.spigot.util.reflection.manager.ReflectionManager; +import java.util.concurrent.ExecutorService; +import me.frep.vulcan.spigot.gui.manager.GUIManager; +import me.frep.vulcan.spigot.punishment.PunishmentManager; +import me.frep.vulcan.spigot.alert.AlertManager; +import me.frep.vulcan.spigot.data.manager.PlayerDataManager; +import me.frep.vulcan.spigot.packet.processor.SendingPacketProcessor; +import me.frep.vulcan.spigot.packet.processor.ReceivingPacketProcessor; +import org.bukkit.plugin.PluginManager; +import me.frep.vulcan.spigot.reset.ResetManager; +import me.frep.vulcan.spigot.brand.ClientBrandManager; +import me.frep.vulcan.spigot.tick.TickManager; +import java.util.Map; +import java.util.logging.Logger; +import me.frep.vulcan.spigot.hook.discord.DiscordHelper; + +public enum Vulcan +{ + INSTANCE; + + private VulcanPlugin plugin; + private DiscordHelper discordHelper; + private long startTime; + private final String spigot; + private final String nonce; + private final String resource; + private final Logger logger; + private boolean floodgate1; + private boolean floodgate2; + private boolean placeHolderAPI; + private boolean mcMMO; + private boolean crackShot; + private boolean libsDisguises; + private boolean mythicMobs; + private boolean gSit; + private boolean brewery; + private boolean testServer; + private boolean mythicMobsLatest; + private final Map fishingRodPulledBoats; + private final TickManager tickManager; + private final ClientBrandManager clientBrandManager; + private final ResetManager resetManager; + private final PluginManager pluginManager; + private final ReceivingPacketProcessor receivingPacketProcessor; + private final SendingPacketProcessor sendingPacketProcessor; + private final PlayerDataManager playerDataManager; + private AlertManager alertManager; + private final PunishmentManager punishmentManager; + private final GUIManager guiManager; + private final ExecutorService judgementExecutor; + private final ExecutorService alertExecutor; + private final ExecutorService packetExecutor; + private final ExecutorService logExecutor; + private final ReflectionManager reflectionManager; + private final boolean bypass = true; + + private Vulcan() { + this.spigot = ID.spigot(); + this.nonce = ID.nonce(); + this.resource = ID.resource(); + this.logger = Bukkit.getLogger(); + this.fishingRodPulledBoats = new HashMap(); + this.tickManager = new TickManager(); + this.clientBrandManager = new ClientBrandManager(); + this.resetManager = new ResetManager(); + this.pluginManager = Bukkit.getServer().getPluginManager(); + this.receivingPacketProcessor = new ReceivingPacketProcessor(); + this.sendingPacketProcessor = new SendingPacketProcessor(); + this.playerDataManager = new PlayerDataManager(); + this.punishmentManager = new PunishmentManager(); + this.guiManager = new GUIManager(); + this.judgementExecutor = Executors.newSingleThreadExecutor(); + this.alertExecutor = Executors.newSingleThreadExecutor(); + this.packetExecutor = Executors.newSingleThreadExecutor(); + this.logExecutor = Executors.newSingleThreadExecutor(); + this.reflectionManager = new ReflectionManager(); + } + + public void start(final VulcanPlugin plugin) { + this.plugin = plugin; + assert plugin != null : "Error while starting Vulcan!"; + this.alertManager = new AlertManager(); + this.getPlugin().saveDefaultConfig(); + Config.initialize(); + Config.updateConfig(); + Stats.initialize(); + CheckManager.setup(); + this.log("Server Version: " + ServerUtil.getServerVersion().toString().replaceAll("_", ".").replaceAll("v", "").replaceFirst(".", "") + " detected!"); + if (this.pluginManager.getPlugin("floodgate-bukkit") != null) { + this.floodgate1 = true; + this.log("Floodgate 1.0 found. Enabling hook!"); + } + if (this.pluginManager.getPlugin("floodgate") != null) { + this.floodgate2 = true; + this.log("Floodgate 2.0 found. Enabling hook!"); + } + if (this.pluginManager.getPlugin("mcMMO") != null) { + this.mcMMO = true; + this.log("mcMMO found. Enabling hook!"); + } + if (this.pluginManager.getPlugin("Crackshot") != null) { + this.crackShot = true; + } + if (this.pluginManager.getPlugin("LibsDisguises") != null) { + this.libsDisguises = true; + this.log("LibsDisguises found. Enabling hook!"); + } + if (this.pluginManager.getPlugin("MythicMobs") != null) { + final Plugin mythicMobsPlugin = Bukkit.getPluginManager().getPlugin("MythicMobs"); + this.mythicMobsLatest = mythicMobsPlugin.getDescription().getVersion().startsWith("5"); + this.mythicMobs = true; + this.log("MythicMobs found. Enabling hook!"); + } + if (this.pluginManager.getPlugin("GSit") != null) { + this.gSit = true; + this.log("GSit found. Enabling hook!"); + } + if (this.pluginManager.getPlugin("Brewery") != null) { + this.brewery = true; + this.log("Brewery found. Enabling hook!"); + } + this.getPlugin().getCommand("punishlogs").setExecutor(new PunishLogs()); + this.getPlugin().getCommand("verbose").setExecutor(new VerboseCommand()); + this.getPlugin().getCommand("alerts").setExecutor(new AlertsCommand()); + this.getPlugin().getCommand("vulcan").setExecutor(new VulcanCommand()); + this.getPlugin().getCommand("vulcan").setTabCompleter(new VulcanTabCompleter()); + this.getPlugin().getCommand("jday").setExecutor(new JDayCommand()); + this.getPlugin().getCommand("logs").setExecutor(new LogsCommand()); + this.getPlugin().getServer().getMessenger().registerOutgoingPluginChannel(plugin, "vulcan:bungee"); + if (Config.BSTATS) { + final Metrics metrics = new Metrics(plugin, 10297); + this.log("BStats enabled!"); + } + this.tickManager.start(); + this.resetManager.start(); + if (Config.CLIENT_BRAND_RESOLVE) { + if (ServerUtil.isHigherThan1_13()) { + Bukkit.getMessenger().registerIncomingPluginChannel(plugin, "minecraft:brand", new ClientBrandListener()); + } + else { + Bukkit.getMessenger().registerIncomingPluginChannel(plugin, "MC|Brand", new ClientBrandListener()); + } + } + this.startTime = System.currentTimeMillis(); + this.pluginManager.registerEvents(new PlayerListener(), plugin); + this.pluginManager.registerEvents(new EventProcessor(), plugin); + this.pluginManager.registerEvents(new GUIManager(), plugin); + if (this.mcMMO && Config.HOOK_MCMMO) { + this.pluginManager.registerEvents(new McMMOHook(), plugin); + this.log("Registered mcMMO listener!"); + } + if (this.crackShot) { + this.pluginManager.registerEvents(new CrackShotHook(), plugin); + this.log("Registered CrackShot listener!"); + } + if (this.mythicMobs && Config.HOOK_MYTHICMOBS) { + this.pluginManager.registerEvents(new MythicMobsHook(), plugin); + this.log("Registered MythicMobs listener!"); + } + if (this.gSit && Config.HOOK_GSIT) { + this.pluginManager.registerEvents(new GSitListener(), plugin); + this.log("Registered GSit Listener!"); + } + if (this.brewery && Config.HOOK_BREWERY) { + this.pluginManager.registerEvents(new BreweryHook(), plugin); + this.log("Registered Brewery Listener"); + } + if (ServerUtil.isHigherThan1_11()) { + Bukkit.getPluginManager().registerEvents(new EventProcessor1_11(), plugin); + } + if (ServerUtil.isHigherThan1_13()) { + Bukkit.getPluginManager().registerEvents(new EventProcessor1_13(), plugin); + } + System.setProperty("com.viaversion.handlePingsAsInvAcknowledgements", "true"); + PacketEvents.get().registerListener(new NetworkManager(PacketEventPriority.LOWEST)); + if (this.getPluginManager().getPlugin("DiscordBotAPI") != null && Config.getBoolean("hooks.discord.enable-hook")) { + this.discordHelper = new DiscordHelper(); + this.log("DiscordBotAPI found. Enabling hook!"); + } + if (this.getPluginManager().getPlugin("PlaceholderAPI") != null) { + this.placeHolderAPI = true; + new PlaceholderAPIExtension().register(); + this.log("PlaceholderAPI found. Enabling hook!"); + } + } + + public void stop(final VulcanPlugin plugin) { + this.plugin = plugin; + assert plugin != null : "Error while shutting down Vulcan."; + this.tickManager.stop(); + this.resetManager.stop(); + this.judgementExecutor.shutdownNow(); + this.packetExecutor.shutdownNow(); + this.logExecutor.shutdownNow(); + this.alertExecutor.shutdownNow(); + Bukkit.getScheduler().cancelTasks(plugin); + } + + public void reload() { + Config.reload(); + Config.updateConfig(); + CacheUtil.resetConfigValues(); + CacheUtil.updateCheckValues(); + if (Vulcan.INSTANCE.getDiscordHelper() != null) { + DiscordHelper.getInstance().updateConfig(); + } + Vulcan.INSTANCE.getPlugin().reloadConfig(); + } + + public void log(final String string) { + Bukkit.getLogger().log(Level.INFO, "[Vulcan] " + string); + } + + public DiscordHelper getDiscordHelper() { + return this.discordHelper; + } + + public long getStartTime() { + return this.startTime; + } + + public String getSpigot() { + return this.spigot; + } + + public String getNonce() { + return this.nonce; + } + + public String getResource() { + return this.resource; + } + + public Logger getLogger() { + return this.logger; + } + + public boolean isFloodgate1() { + return this.floodgate1; + } + + public boolean isFloodgate2() { + return this.floodgate2; + } + + public boolean isPlaceHolderAPI() { + return this.placeHolderAPI; + } + + public boolean isMcMMO() { + return this.mcMMO; + } + + public boolean isCrackShot() { + return this.crackShot; + } + + public boolean isLibsDisguises() { + return this.libsDisguises; + } + + public boolean isMythicMobs() { + return this.mythicMobs; + } + + public boolean isGSit() { + return this.gSit; + } + + public boolean isBrewery() { + return this.brewery; + } + + public boolean isTestServer() { + return this.testServer; + } + + public boolean isMythicMobsLatest() { + return this.mythicMobsLatest; + } + + public Map getFishingRodPulledBoats() { + return this.fishingRodPulledBoats; + } + + public TickManager getTickManager() { + return this.tickManager; + } + + public ClientBrandManager getClientBrandManager() { + return this.clientBrandManager; + } + + public ResetManager getResetManager() { + return this.resetManager; + } + + public PluginManager getPluginManager() { + return this.pluginManager; + } + + public ReceivingPacketProcessor getReceivingPacketProcessor() { + return this.receivingPacketProcessor; + } + + public SendingPacketProcessor getSendingPacketProcessor() { + return this.sendingPacketProcessor; + } + + public PlayerDataManager getPlayerDataManager() { + return this.playerDataManager; + } + + public AlertManager getAlertManager() { + return this.alertManager; + } + + public PunishmentManager getPunishmentManager() { + return this.punishmentManager; + } + + public GUIManager getGuiManager() { + return this.guiManager; + } + + public ExecutorService getJudgementExecutor() { + return this.judgementExecutor; + } + + public ExecutorService getAlertExecutor() { + return this.alertExecutor; + } + + public ExecutorService getPacketExecutor() { + return this.packetExecutor; + } + + public ExecutorService getLogExecutor() { + return this.logExecutor; + } + + public ReflectionManager getReflectionManager() { + return this.reflectionManager; + } + + public boolean isBypass() { + Objects.requireNonNull(this); + return true; + } + + public VulcanPlugin getPlugin() { + return this.plugin; + } + + public void setFloodgate1(final boolean floodgate1) { + this.floodgate1 = floodgate1; + } + + public void setFloodgate2(final boolean floodgate2) { + this.floodgate2 = floodgate2; + } + + public void setPlaceHolderAPI(final boolean placeHolderAPI) { + this.placeHolderAPI = placeHolderAPI; + } + + public void setMcMMO(final boolean mcMMO) { + this.mcMMO = mcMMO; + } + + public void setCrackShot(final boolean crackShot) { + this.crackShot = crackShot; + } + + public void setLibsDisguises(final boolean libsDisguises) { + this.libsDisguises = libsDisguises; + } + + public void setMythicMobs(final boolean mythicMobs) { + this.mythicMobs = mythicMobs; + } + + public void setGSit(final boolean gSit) { + this.gSit = gSit; + } + + public void setBrewery(final boolean brewery) { + this.brewery = brewery; + } + + public void setTestServer(final boolean testServer) { + this.testServer = testServer; + } + + public void setMythicMobsLatest(final boolean mythicMobsLatest) { + this.mythicMobsLatest = mythicMobsLatest; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/VulcanPlugin.java b/src/main/java/me/frep/vulcan/spigot/VulcanPlugin.java new file mode 100644 index 0000000..1222e8a --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/VulcanPlugin.java @@ -0,0 +1,28 @@ +package me.frep.vulcan.spigot; + +import me.frep.vulcan.api.VulcanAPI; +import me.frep.vulcan.spigot.api.VulcanSpigotAPI; +import org.bukkit.plugin.Plugin; +import io.github.retrooper.packetevents.PacketEvents; +import org.bukkit.plugin.java.JavaPlugin; + +public final class VulcanPlugin extends JavaPlugin +{ + public void onLoad() { + PacketEvents.create(this); + PacketEvents.get().getSettings().compatInjector(!this.getConfig().getBoolean("settings.inject-early")); + PacketEvents.get().getSettings().checkForUpdates(false); + PacketEvents.get().load(); + } + + public void onEnable() { + PacketEvents.get().init(); + VulcanAPI.Factory.setApi(new VulcanSpigotAPI()); + Vulcan.INSTANCE.start(this); + } + + public void onDisable() { + PacketEvents.get().terminate(); + Vulcan.INSTANCE.stop(this); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/alert/AlertManager.java b/src/main/java/me/frep/vulcan/spigot/alert/AlertManager.java new file mode 100644 index 0000000..6bf9095 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/alert/AlertManager.java @@ -0,0 +1,575 @@ +package me.frep.vulcan.spigot.alert; + +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; +import java.util.Iterator; +import me.frep.vulcan.spigot.jday.JDay; +import java.awt.Color; +import me.frep.vulcan.spigot.util.discord.DiscordWebhook; +import me.frep.vulcan.spigot.hook.discord.DiscordHelper; +import net.md_5.bungee.api.chat.BaseComponent; +import me.frep.vulcan.api.event.VulcanPostFlagEvent; +import net.md_5.bungee.api.chat.ComponentBuilder; +import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.TextComponent; +import me.clip.placeholderapi.PlaceholderAPI; +import org.apache.commons.lang.StringUtils; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.util.LogUtil; +import me.frep.vulcan.api.event.VulcanSetbackEvent; +import me.frep.vulcan.api.check.Check; +import me.frep.vulcan.api.event.VulcanFlagEvent; +import me.frep.vulcan.spigot.util.PlayerUtil; +import org.geysermc.floodgate.api.FloodgateApi; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.AbstractCheck; +import me.frep.vulcan.api.event.VulcanEnableAlertsEvent; +import org.bukkit.plugin.Plugin; +import org.bukkit.event.Event; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.Bukkit; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.api.event.VulcanDisableAlertsEvent; +import me.frep.vulcan.spigot.util.ColorUtil; +import me.frep.vulcan.spigot.config.Config; +import java.util.HashSet; +import java.text.DecimalFormat; +import org.bukkit.entity.Player; +import java.util.Set; + +public class AlertManager +{ + private final Set alertsEnabled; + private final Set verboseEnabled; + private final DecimalFormat format; + + public AlertManager() { + this.alertsEnabled = new HashSet(); + this.verboseEnabled = new HashSet(); + this.format = new DecimalFormat("##.##"); + } + + public void toggleAlerts(final Player player) { + if (this.alertsEnabled.contains(player)) { + this.alertsEnabled.remove(player); + player.sendMessage(ColorUtil.translate(Config.ALERTS_DISABLED)); + if (Config.ENABLE_API) { + final VulcanDisableAlertsEvent event = new VulcanDisableAlertsEvent(player); + if (ServerUtil.isHigherThan1_13()) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> Bukkit.getPluginManager().callEvent(event)); + } + else { + Bukkit.getPluginManager().callEvent(event); + } + } + } + else { + this.alertsEnabled.add(player); + player.sendMessage(ColorUtil.translate(Config.ALERTS_ENABLED)); + if (Config.ENABLE_API) { + final VulcanEnableAlertsEvent event = new VulcanEnableAlertsEvent(player); + if (ServerUtil.isHigherThan1_13()) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> Bukkit.getPluginManager().callEvent(event)); + } + else { + Bukkit.getPluginManager().callEvent(event); + } + } + } + } + + public void toggleVerbose(final Player player) { + if (this.verboseEnabled.contains(player)) { + this.verboseEnabled.remove(player); + player.sendMessage(ColorUtil.translate(Config.VERBOSE_DISABLED)); + } + else { + this.verboseEnabled.add(player); + player.sendMessage(ColorUtil.translate(Config.VERBOSE_ENABLED)); + } + } + + public void handleAlert(final AbstractCheck check, final PlayerData data, final String info) { + if (Vulcan.INSTANCE.isTestServer()) { + return; + } + if (!Config.ENABLED_CHECKS.get(check.getClassName())) { + return; + } + if (System.currentTimeMillis() - data.getLastPunishment() < Config.PUNISHMENT_DELAY) { + return; + } + if (!data.getPlayer().isOnline()) { + return; + } + if (Config.IGNORE_FLOODGATE && Vulcan.INSTANCE.isFloodgate2() && FloodgateApi.getInstance().isFloodgatePlayer(data.getPlayer().getUniqueId())) { + return; + } + if (ServerUtil.getTPS() < Config.MINIMUM_TPS.get(check.getClassName())) { + return; + } + if (PlayerUtil.getPing(data.getPlayer()) > Config.MAXIMUM_PING.get(check.getClassName())) { + return; + } + if (Config.IGNORE_VIVECRAFT && data.getClientBrand().toLowerCase().contains("vivecraft")) { + return; + } + if (data.getPlayer().hasPermission("vulcan.bypass." + check.getClassName().toLowerCase())) { + return; + } + if (Config.IGNORE_GEYSER_CLIENT_BRAND && data.getClientBrand().toLowerCase().contains("geyser")) { + return; + } + if (Config.IGNORE_GEYSER_UUIDS && data.getPlayer().getUniqueId().toString().startsWith("00000")) { + return; + } + if (Config.IGNORE_GEYSER_PREFIXES && data.getPlayer().getName().startsWith(Config.IGNORE_GEYSER_PREFIX)) { + return; + } + if (Config.ENABLE_API) { + final VulcanFlagEvent event = new VulcanFlagEvent(data.getPlayer(), check, info); + Bukkit.getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + } + if (Config.SETBACKS.get(check.getClassName()) && check.getVl() > Config.MINIMUM_VIOLATIONS_TO_SETBACK.get(check.getClassName())) { + if (Config.ENABLE_API) { + final VulcanSetbackEvent event2 = new VulcanSetbackEvent(data.getPlayer(), check); + Bukkit.getPluginManager().callEvent(event2); + if (!event2.isCancelled()) { + data.getPositionProcessor().setback(); + } + } + else if (!data.getPlayer().hasPermission("vulcan.bypass.setback." + check.getClassName().toLowerCase())) { + data.getPositionProcessor().setback(); + } + } + if (check.getCategory().equals("movement")) { + data.getPositionProcessor().setSinceFlagTicks(0); + } + check.setVl(check.getVl() + 1); + final int vl = check.getVl(); + if (!check.isExperimental()) { + if (!check.getName().equalsIgnoreCase("timer")) { + data.setTotalViolations(data.getTotalViolations() + 1); + } + if (check.getName().equalsIgnoreCase("timer")) { + data.setTimerViolations(data.getTimerViolations() + 1); + } + if (check.getName().equalsIgnoreCase("autoclicker")) { + data.setAutoClickerViolations(data.getAutoClickerViolations() + 1); + } + if (check.getName().equalsIgnoreCase("scaffold")) { + data.setScaffoldViolations(data.getScaffoldViolations() + 1); + } + final String category = check.getCategory(); + switch (category) { + case "combat": { + if (!check.getName().equalsIgnoreCase("autoclicker")) { + data.setCombatViolations(data.getCombatViolations() + 1); + break; + } + break; + } + case "movement": { + data.setMovementViolations(data.getMovementViolations() + 1); + break; + } + case "player": { + if (!check.getName().equalsIgnoreCase("timer")) { + data.setPlayerViolations(data.getPlayerViolations() + 1); + break; + } + break; + } + } + } + final int alertInterval = Config.ALERT_INTERVAL.get(check.getClassName()); + final int minimumVlToNotify = Config.MINIMUM_VL_TO_NOTIFY.get(check.getClassName()); + final int totalViolations = data.getTotalViolations(); + final int maxVl = Config.MAX_VIOLATIONS.get(check.getClassName()); + if (vl % alertInterval == 0 && vl >= minimumVlToNotify) { + if (Config.LOG_FILE_ENABLED) { + Vulcan.INSTANCE.getLogExecutor().execute(() -> LogUtil.logAlert(check, data, info)); + } + final String name = data.getPlayer().getName(); + final String description = check.getCheckInfo().description(); + final String checkName = check.getCheckInfo().name(); + final String x = MathUtil.trim(data.getPositionProcessor().getX()); + final String y = MathUtil.trim(data.getPositionProcessor().getY()); + final String z = MathUtil.trim(data.getPositionProcessor().getZ()); + final String world = data.getPlayer().getWorld().getName(); + final String ping = Integer.toString(PlayerUtil.getPing(data.getPlayer())); + final String tps = MathUtil.trim(ServerUtil.getTPS()); + final String vlString = Integer.toString(check.getVl()); + final String totalVlString = Integer.toString(data.getTotalViolations()); + final String maxVlString = Integer.toString(maxVl); + final String version = PlayerUtil.getClientVersionToString(data.getPlayer()); + final String cps = MathUtil.trim(data.getClickProcessor().getCps()); + final String experimental = check.getCheckInfo().experimental() ? ColorUtil.translate(Config.EXPERIMENTAL_SYMBOL) : ""; + int severity = 1; + if (Config.PER_CHECK_SEVERITY) { + if (vl >= Config.ALERTS_SEVERITY_2) { + severity = 2; + } + if (vl >= Config.ALERTS_SEVERITY_3) { + severity = 3; + } + if (vl >= Config.ALERTS_SEVERITY_4) { + severity = 4; + } + if (vl >= Config.ALERTS_SEVERITY_5) { + severity = 5; + } + if (vl >= Config.ALERTS_SEVERITY_6) { + severity = 6; + } + if (vl >= Config.ALERTS_SEVERITY_7) { + severity = 7; + } + if (vl >= Config.ALERTS_SEVERITY_8) { + severity = 8; + } + if (vl >= Config.ALERTS_SEVERITY_9) { + severity = 9; + } + if (vl >= Config.ALERTS_SEVERITY_10) { + severity = 10; + } + } + else { + if (totalViolations >= Config.ALERTS_SEVERITY_2) { + severity = 2; + } + if (totalViolations >= Config.ALERTS_SEVERITY_3) { + severity = 3; + } + if (totalViolations >= Config.ALERTS_SEVERITY_4) { + severity = 4; + } + if (totalViolations >= Config.ALERTS_SEVERITY_5) { + severity = 5; + } + if (totalViolations >= Config.ALERTS_SEVERITY_6) { + severity = 6; + } + if (totalViolations >= Config.ALERTS_SEVERITY_7) { + severity = 7; + } + if (totalViolations >= Config.ALERTS_SEVERITY_8) { + severity = 8; + } + if (totalViolations >= Config.ALERTS_SEVERITY_9) { + severity = 9; + } + if (totalViolations >= Config.ALERTS_SEVERITY_10) { + severity = 10; + } + } + final int finalSeverity = severity; + this.sendPluginMessage(data.getPlayer(), check.getDisplayName() + "#VULCAN#" + check.getDisplayType() + "#VULCAN#" + vlString + "#VULCAN#" + name + "#VULCAN#" + maxVlString + "#VULCAN#" + version + "#VULCAN#" + tps + "#VULCAN#" + ping + "#VULCAN#" + description + "#VULCAN#" + info + "#VULCAN#" + experimental + "#VULCAN#" + this.getSeverity(finalSeverity)); + if (Config.ALERTS_TO_CONSOLE) { + if (!Config.IGNORE_ALERTS_OVER_MAX_VIOLATIONS || vl <= maxVl + Config.IGNORE_ALERTS_OVER_MAX_VIOLATIONS_AMOUNT) { + ServerUtil.log(ColorUtil.translate(Config.ALERTS_CONSOLE_FORMAT).replaceAll("%player%", name).replaceAll("%max-vl%", maxVlString).replaceAll("%check%", checkName).replaceAll("%info%", info).replaceAll("%server-name%", Config.SERVER_NAME).replaceAll("%cps%", cps).replaceAll("%category%", StringUtils.capitalize(check.getCategory().toLowerCase())).replaceAll("%complex-type%", check.getCheckInfo().complexType()).replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%x%", x).replaceAll("%y%", y).replaceAll("%uuid%", data.getPlayer().getUniqueId().toString()).replaceAll("%opponennt%", (data.getCombatProcessor().getTrackedPlayer() == null) ? "None" : data.getCombatProcessor().getTrackedPlayer().getName()).replaceAll("%z%", z).replaceAll("%world%", world).replaceAll("%total-violations%", totalVlString).replaceAll("%ping%", ping).replaceAll("%description%", description).replaceAll("%tps%", tps).replaceAll("%version%", version).replaceAll("%dev%", check.getCheckInfo().experimental() ? ColorUtil.translate(Config.EXPERIMENTAL_SYMBOL) : "").replaceAll("%vl%", vlString).replaceAll("%type%", Character.toString(check.getCheckInfo().type()))); + } + } + Label_2863: { + if (!this.alertsEnabled.isEmpty()) { + if (!Config.IGNORE_ALERTS_OVER_MAX_VIOLATIONS || vl <= maxVl + Config.IGNORE_ALERTS_OVER_MAX_VIOLATIONS_AMOUNT) { + String alertsFormat = ColorUtil.translate(Config.ALERTS_FORMAT); + if (Vulcan.INSTANCE.isPlaceHolderAPI()) { + alertsFormat = PlaceholderAPI.setPlaceholders(data.getPlayer(), alertsFormat); + } + final TextComponent alertMessage = new TextComponent(TextComponent.fromLegacyText(ColorUtil.translate(alertsFormat).replaceAll("%player%", name).replaceAll("%ping%", ping).replaceAll("%tps%", tps).replaceAll("%max-vl%", maxVlString).replaceAll("%severity%", this.getSeverity(finalSeverity)).replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%info%", info).replaceAll("%cps%", cps).replaceAll("%server-name%", Config.SERVER_NAME).replaceAll("%category%", StringUtils.capitalize(check.getCategory().toLowerCase())).replaceAll("%complex-type%", check.getCheckInfo().complexType()).replaceAll("%x%", x).replaceAll("%y%", y).replaceAll("%z%", z).replaceAll("%uuid%", data.getPlayer().getUniqueId().toString()).replaceAll("%opponennt%", (data.getCombatProcessor().getTrackedPlayer() == null) ? "None" : data.getCombatProcessor().getTrackedPlayer().getName()).replaceAll("%world%", world).replaceAll("%total-violations%", totalVlString).replaceAll("%check%", check.getCheckInfo().name()).replaceAll("%description%", check.getCheckInfo().description()).replaceAll("%version%", version).replaceAll("%dev%", check.getCheckInfo().experimental() ? ColorUtil.translate(Config.EXPERIMENTAL_SYMBOL) : "").replaceAll("%vl%", vlString).replaceAll("%type%", Character.toString(check.getCheckInfo().type())))); + for (final String clickCommand : Config.ALERTS_CLICK_COMMANDS) { + alertMessage.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, clickCommand.replaceAll("%player%", data.getPlayer().getName()).replaceAll("%uuid%", data.getPlayer().getUniqueId().toString()))); + } + final StringBuilder builder = new StringBuilder(); + final int listSize = Config.ALERTS_HOVER_MESSAGES.size(); + int i = 1; + for (final String hoverMessages : Config.ALERTS_HOVER_MESSAGES) { + if (i == listSize) { + builder.append(hoverMessages); + } + else { + builder.append(hoverMessages).append("\n"); + } + ++i; + } + String hoverFormat = ColorUtil.translate(builder.toString()); + if (Vulcan.INSTANCE.isPlaceHolderAPI()) { + hoverFormat = PlaceholderAPI.setPlaceholders(data.getPlayer(), hoverFormat); + } + final String hoverMessage = ColorUtil.translate(hoverFormat.replaceAll("%player%", name).replaceAll("%check%", checkName).replaceAll("%max-vl%", maxVlString).replaceAll("%server-name%", Config.SERVER_NAME).replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%severity", this.getSeverity(finalSeverity)).replaceAll("%x%", x).replaceAll("%y%", y).replaceAll("%uuid%", data.getPlayer().getUniqueId().toString()).replaceAll("%category%", StringUtils.capitalize(check.getCategory().toLowerCase())).replaceAll("%z%", z).replaceAll("%world%", world).replaceAll("%vl%", vlString).replaceAll("%combat-violations%", Integer.toString(data.getCombatViolations())).replaceAll("%movement-violations%", Integer.toString(data.getMovementViolations())).replaceAll("%player-violations%", Integer.toString(data.getPlayerViolations())).replaceAll("%cps%", cps).replaceAll("%complex-type%", check.getCheckInfo().complexType()).replaceAll("%version%", version).replaceAll("%total-violations%", totalVlString).replaceAll("%ping%", ping).replaceAll("%opponennt%", (data.getCombatProcessor().getTrackedPlayer() == null) ? "None" : data.getCombatProcessor().getTrackedPlayer().getName()).replaceAll("%description%", description).replaceAll("%dev%", check.getCheckInfo().experimental() ? ColorUtil.translate(Config.EXPERIMENTAL_SYMBOL) : "").replaceAll("%type%", Character.toString(check.getCheckInfo().type())).replaceAll("%tps%", tps).replaceAll("%info%", info).replaceAll("%check%", check.getCheckInfo().name())); + if (ServerUtil.isHigherThan1_16()) { + alertMessage.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.fromLegacyText(hoverMessage))); + } + else { + alertMessage.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder(hoverMessage).create())); + } + if (Config.ENABLE_API) { + final VulcanPostFlagEvent event3 = new VulcanPostFlagEvent(data.getPlayer(), check, info); + Bukkit.getPluginManager().callEvent(event3); + if (event3.isCancelled()) { + break Label_2863; + } + } + if (Config.ASYNC_ALERTS) { + this.alertsEnabled.forEach(player -> player.spigot().sendMessage(alertMessage)); + } + else { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.alertsEnabled.forEach(player -> player.spigot().sendMessage(alertMessage))); + } + } + } + } + if (!Config.ALERTS_CUSTOM_COMMANDS.isEmpty()) { + if (Vulcan.INSTANCE.isPlaceHolderAPI()) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> Config.ALERTS_CUSTOM_COMMANDS.forEach(command -> ServerUtil.dispatchCommand(PlaceholderAPI.setPlaceholders(data.getPlayer(), command.replaceAll("%player%", name).replaceAll("%max-vl%", maxVlString).replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%category%", StringUtils.capitalize(check.getCategory().toLowerCase())).replaceAll("%server-name%", Config.SERVER_NAME).replaceAll("%info%", info).replaceAll("%complex-type%", check.getCheckInfo().complexType()).replaceAll("%check%", check.getCheckInfo().name()).replaceAll("%ping%", ping).replaceAll("%description%", check.getCheckInfo().description()).replaceAll("%x%", x).replaceAll("%uuid%", data.getPlayer().getUniqueId().toString()).replaceAll("%opponennt%", (data.getCombatProcessor().getTrackedPlayer() == null) ? "None" : data.getCombatProcessor().getTrackedPlayer().getName()).replaceAll("%y%", y).replaceAll("%z%", z).replaceAll("%cps%", cps).replaceAll("%world%", world).replaceAll("%total-violations%", Integer.toString(data.getTotalViolations())).replaceAll("%tps%", tps).replaceAll("%version%", version).replaceAll("%dev%", check.getCheckInfo().experimental() ? ColorUtil.translate(Config.EXPERIMENTAL_SYMBOL) : "").replaceAll("%vl%", vlString).replaceAll("%type%", Character.toString(check.getCheckInfo().type())))))); + } + else { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> Config.ALERTS_CUSTOM_COMMANDS.forEach(command -> ServerUtil.dispatchCommand(command.replaceAll("%player%", name).replaceAll("%max-vl%", maxVlString).replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%server-name%", Config.SERVER_NAME).replaceAll("%info%", info).replaceAll("%opponennt%", (data.getCombatProcessor().getTrackedPlayer() == null) ? "None" : data.getCombatProcessor().getTrackedPlayer().getName()).replaceAll("%complex-type%", check.getCheckInfo().complexType()).replaceAll("%check%", check.getCheckInfo().name()).replaceAll("%ping%", ping).replaceAll("%description%", check.getCheckInfo().description()).replaceAll("%x%", x).replaceAll("%y%", y).replaceAll("%z%", z).replaceAll("%uuid%", data.getPlayer().getUniqueId().toString()).replaceAll("%category%", StringUtils.capitalize(check.getCategory().toLowerCase())).replaceAll("%cps%", cps).replaceAll("%world%", world).replaceAll("%total-violations%", Integer.toString(data.getTotalViolations())).replaceAll("%tps%", tps).replaceAll("%version%", version).replaceAll("%dev%", check.getCheckInfo().experimental() ? ColorUtil.translate(Config.EXPERIMENTAL_SYMBOL) : "").replaceAll("%vl%", vlString).replaceAll("%type%", Character.toString(check.getCheckInfo().type()))))); + } + } + if (Vulcan.INSTANCE.getDiscordHelper() != null) { + final int discordAlertInterval = Config.DISCORD_ALERT_INTERVAL.get(check.getClassName()); + if (vl % discordAlertInterval == 0) { + DiscordHelper.getInstance().sendDiscordAlertMessage(check, data, info); + } + } + if (Config.ALERTS_WEBHOOK) { + if (!Config.ALERTS_WEBHOOK_URL.equalsIgnoreCase("insert-url-here")) { + final int discordAlertInterval = Config.DISCORD_ALERT_INTERVAL.get(check.getClassName()); + if (vl % discordAlertInterval == 0) { + final DiscordWebhook webhook = new DiscordWebhook(Config.ALERTS_WEBHOOK_URL); + webhook.setAvatarUrl(Config.ALERTS_WEBHOOK_AVATAR_URL); + webhook.setUsername(Config.ALERTS_WEBHOOK_USERNAME); + final DiscordWebhook.EmbedObject embedObject = new DiscordWebhook.EmbedObject(); + embedObject.setTitle(Config.ALERTS_WEBHOOK_TITLE); + embedObject.setThumbnail(Config.ALERTS_WEBHOOK_THUMBNAIL.replaceAll("%uuid%", data.getPlayer().getUniqueId().toString()).replaceAll("%name%", data.getPlayer().getName())); + embedObject.setColor(new Color(Config.ALERTS_WEBHOOK_COLOR_R, Config.ALERTS_WEBHOOK_COLOR_G, Config.ALERTS_WEBHOOK_COLOR_B)); + embedObject.setDescription(Config.ALERTS_WEBHOOK_DESCRIPTION.replaceAll("%player%", name).replaceAll("%player%", name).replaceAll("%check%", checkName).replaceAll("%max-vl%", maxVlString).replaceAll("%server-name%", Config.SERVER_NAME).replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%x%", x).replaceAll("%uuid%", data.getPlayer().getUniqueId().toString()).replaceAll("%y%", y).replaceAll("%category%", StringUtils.capitalize(check.getCategory().toLowerCase())).replaceAll("%z%", z).replaceAll("%client-version%", PlayerUtil.getClientVersionToString(data.getPlayer())).replaceAll("%world%", world).replaceAll("%vl%", vlString).replaceAll("%cps%", cps).replaceAll("%complex-type%", check.getCheckInfo().complexType()).replaceAll("%version%", version).replaceAll("%total-violations%", totalVlString).replaceAll("%ping%", ping).replaceAll("%opponent%", (data.getCombatProcessor().getTrackedPlayer() == null) ? "None" : data.getCombatProcessor().getTrackedPlayer().getName()).replaceAll("%description%", description).replaceAll("%dev%", check.getCheckInfo().experimental() ? ColorUtil.translate(Config.EXPERIMENTAL_SYMBOL) : "").replaceAll("%type%", Character.toString(check.getCheckInfo().type())).replaceAll("%tps%", tps).replaceAll("%info%", info).replaceAll("%check%", checkName)); + if (Config.ALERTS_WEBHOOK_DESCRIPTION_FIELD) { + embedObject.addField("Description", description, true); + } + if (Config.ALERTS_WEBHOOK_INFORMATION_FIELD) { + embedObject.addField("Information", info, true); + } + if (Config.ALERTS_WEBHOOK_SERVER_NAME_FIELD) { + embedObject.addField("Server Name", Config.SERVER_NAME, true); + } + if (Config.ALERTS_WEBHOOK_CLIENT_BRAND_FIELD) { + embedObject.addField("Client Brand", data.getClientBrand(), true); + } + if (Config.ALERTS_WEBHOOK_CLIENT_VERSION_FIELD) { + embedObject.addField("Client Version", PlayerUtil.getClientVersionToString(data.getPlayer()), true); + } + if (Config.ALERTS_WEBHOOK_PING_TPS_FIELD) { + embedObject.addField("Ping | TPS", data.getConnectionProcessor().getKeepAlivePing() + "ms | " + MathUtil.trim(ServerUtil.getTPS()), true); + } + if (Config.ALERTS_WEBHOOK_LOCATION_FIELD) { + embedObject.addField("Location", "(" + world + ", " + data.getPositionProcessor().getBlockX() + ", " + data.getPositionProcessor().getBlockY() + ", " + data.getPositionProcessor().getBlockZ() + ")", true); + } + webhook.addEmbed(embedObject); + if (!Config.ALERTS_WEBHOOK_CONTENT.equals("")) { + webhook.setContent(Config.ALERTS_WEBHOOK_CONTENT.replaceAll("%player%", name).replaceAll("%player%", name).replaceAll("%check%", checkName).replaceAll("%max-vl%", maxVlString).replaceAll("%server-name%", Config.SERVER_NAME).replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%x%", x).replaceAll("%y%", y).replaceAll("%cps%", Double.toString(MathUtil.round(data.getClickProcessor().getCps(), 2))).replaceAll("%category%", StringUtils.capitalize(check.getCategory().toLowerCase())).replaceAll("%z%", z).replaceAll("%uuid%", data.getPlayer().getUniqueId().toString()).replaceAll("%world%", world).replaceAll("%vl%", vlString).replaceAll("%cps%", cps).replaceAll("%complex-type%", check.getCheckInfo().complexType()).replaceAll("%version%", version).replaceAll("%total-violations%", totalVlString).replaceAll("%ping%", ping).replaceAll("%opponennt%", (data.getCombatProcessor().getTrackedPlayer() == null) ? "None" : data.getCombatProcessor().getTrackedPlayer().getName()).replaceAll("%description%", description).replaceAll("%dev%", check.getCheckInfo().experimental() ? ColorUtil.translate(Config.EXPERIMENTAL_SYMBOL) : "").replaceAll("%type%", Character.toString(check.getCheckInfo().type())).replaceAll("%tps%", tps).replaceAll("%info%", info).replaceAll("%check%", checkName)); + } + try { + webhook.execute(); + } + catch (final Exception ex) {} + } + } + } + } + if (Config.PUNISHABLE.get(check.getClassName()) && !check.getCheckInfo().experimental()) { + if (!Config.IGNORE_IN_JUDGEMENT_DAY || !JDay.isInBanWave(data.getPlayer())) { + if (vl >= maxVl && data.getPlayer().isOnline()) { + Vulcan.INSTANCE.getPunishmentManager().handlePunishment(check, data); + } + } + } + } + + public void handleVerbose(final AbstractCheck check, final PlayerData data) { + if (Vulcan.INSTANCE.isTestServer()) { + return; + } + if (this.verboseEnabled.isEmpty()) { + return; + } + final int maxVl = Config.MAX_VIOLATIONS.get(check.getClassName()); + final TextComponent verboseMessage = new TextComponent(ColorUtil.translate(Config.VERBOSE_FORMAT).replaceAll("%player%", data.getPlayer().getName()).replaceAll("%percent%", this.format.format(check.getBuffer() / check.getMAX_BUFFER() * 100.0)).replaceAll("%max-vl%", Integer.toString(maxVl)).replaceAll("%category%", StringUtils.capitalize(check.getCategory().toLowerCase())).replaceAll("%server-name%", Config.SERVER_NAME).replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%tps%", MathUtil.trim(ServerUtil.getTPS())).replaceAll("%opponennt%", (data.getCombatProcessor().getTrackedPlayer() == null) ? "None" : data.getCombatProcessor().getTrackedPlayer().getName()).replaceAll("%ping%", Integer.toString(PlayerUtil.getPing(data.getPlayer()))).replaceAll("%complex-type%", check.getCheckInfo().complexType()).replaceAll("%cps%", Double.toString(data.getClickProcessor().getCps())).replaceAll("%total-violations%", Integer.toString(data.getTotalViolations())).replaceAll("%x%", MathUtil.trim(data.getPositionProcessor().getX())).replaceAll("%cps%", Double.toString(MathUtil.round(data.getClickProcessor().getCps(), 2))).replaceAll("%y%", MathUtil.trim(data.getPositionProcessor().getY())).replaceAll("%z%", MathUtil.trim(data.getPositionProcessor().getZ())).replaceAll("%world%", data.getPlayer().getWorld().getName()).replaceAll("%buffer%", this.format.format(check.getBuffer())).replaceAll("%max-buffer%", this.format.format(check.getMAX_BUFFER())).replaceAll("%check%", check.getCheckInfo().name()).replaceAll("%description%", check.getCheckInfo().description()).replaceAll("%version%", PlayerUtil.getClientVersionToString(data.getPlayer())).replaceAll("%dev%", check.getCheckInfo().experimental() ? ColorUtil.translate(Config.EXPERIMENTAL_SYMBOL) : "").replaceAll("%vl%", Integer.toString(check.getVl())).replaceAll("%type%", Character.toString(check.getCheckInfo().type()))); + for (final String clickCommands : Config.VERBOSE_CLICK_COMMANDS) { + verboseMessage.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, clickCommands.replaceAll("%player%", data.getPlayer().getName()))); + } + final StringBuilder builder = new StringBuilder(); + final int listSize = Config.VERBOSE_HOVER_MESSAGES.size(); + int i = 1; + for (final String hoverMessages : Config.VERBOSE_HOVER_MESSAGES) { + if (i == listSize) { + builder.append(hoverMessages); + } + else { + builder.append(hoverMessages + "\n"); + } + ++i; + } + verboseMessage.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder(ColorUtil.translate(builder.toString().replaceAll("%player%", data.getPlayer().getName()).replaceAll("%version%", PlayerUtil.getClientVersionToString(data.getPlayer())).replaceAll("%total-violations%", Integer.toString(data.getTotalViolations())).replaceAll("%buffer%", MathUtil.trim(check.getBuffer())).replaceAll("%opponennt%", (data.getCombatProcessor().getTrackedPlayer() == null) ? "None" : data.getCombatProcessor().getTrackedPlayer().getName()).replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%server-name%", Config.SERVER_NAME).replaceAll("%x%", MathUtil.trim(data.getPositionProcessor().getX())).replaceAll("%cps%", Double.toString(data.getClickProcessor().getCps())).replaceAll("%y%", MathUtil.trim(data.getPositionProcessor().getY())).replaceAll("%category%", StringUtils.capitalize(check.getCategory().toLowerCase())).replaceAll("%z%", MathUtil.trim(data.getPositionProcessor().getZ())).replaceAll("%world%", data.getPlayer().getWorld().getName()).replaceAll("%complex-type%", check.getCheckInfo().complexType()).replaceAll("%max-buffer%", MathUtil.trim(check.getMAX_BUFFER())).replaceAll("%percent%", Double.toString(check.getBuffer() / check.getMAX_BUFFER())).replaceAll("%ping%", Integer.toString(PlayerUtil.getPing(data.getPlayer()))).replaceAll("%description%", check.getCheckInfo().description()).replaceAll("%tps%", this.format.format(ServerUtil.getTPS())).replaceAll("%check%", check.getCheckInfo().name()))).create())); + if (Config.ASYNC_ALERTS) { + this.verboseEnabled.forEach(player -> player.spigot().sendMessage(verboseMessage)); + } + else { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.verboseEnabled.forEach(player -> player.spigot().sendMessage(verboseMessage))); + } + } + + public void handleApiAlert(final Player player, final String checkName, final String checkType, final String info) { + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + if (Config.IGNORE_FLOODGATE && Vulcan.INSTANCE.isFloodgate2() && FloodgateApi.getInstance().isFloodgatePlayer(data.getPlayer().getUniqueId())) { + return; + } + if (Config.IGNORE_VIVECRAFT && data.getClientBrand().toLowerCase().contains("vivecraft")) { + return; + } + if (Config.IGNORE_GEYSER_CLIENT_BRAND && data.getClientBrand().toLowerCase().contains("geyser")) { + return; + } + if (Config.IGNORE_GEYSER_UUIDS && data.getPlayer().getUniqueId().toString().startsWith("00000")) { + return; + } + if (Config.IGNORE_GEYSER_PREFIXES && data.getPlayer().getName().startsWith(Config.IGNORE_GEYSER_PREFIX)) { + return; + } + final String name = data.getPlayer().getName(); + final String x = MathUtil.trim(data.getPositionProcessor().getX()); + final String y = MathUtil.trim(data.getPositionProcessor().getY()); + final String z = MathUtil.trim(data.getPositionProcessor().getZ()); + final String world = data.getPlayer().getWorld().getName(); + final String ping = Integer.toString(PlayerUtil.getPing(data.getPlayer())); + final String tps = MathUtil.trim(ServerUtil.getTPS()); + final String totalVlString = Integer.toString(data.getTotalViolations()); + final String version = PlayerUtil.getClientVersionToString(data.getPlayer()); + final String cps = MathUtil.trim(data.getClickProcessor().getCps()); + if (Config.ALERTS_TO_CONSOLE) { + ServerUtil.log(ColorUtil.translate(Config.ALERTS_CONSOLE_FORMAT).replaceAll("%player%", name).replaceAll("%check%", checkName).replaceAll("%type%", checkType).replaceAll("%info%", info).replaceAll("%server-name%", Config.SERVER_NAME).replaceAll("%cps%", cps).replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%x%", x).replaceAll("%y%", y).replaceAll("%opponennt%", (data.getCombatProcessor().getTrackedPlayer() == null) ? "None" : data.getCombatProcessor().getTrackedPlayer().getName()).replaceAll("%z%", z).replaceAll("%world%", world).replaceAll("%total-violations%", totalVlString).replaceAll("%ping%", ping).replaceAll("%tps%", tps).replaceAll("%version%", version)); + if (!this.alertsEnabled.isEmpty()) { + String alertsFormat = ColorUtil.translate(Config.ALERTS_FORMAT); + if (Vulcan.INSTANCE.isPlaceHolderAPI()) { + alertsFormat = PlaceholderAPI.setPlaceholders(data.getPlayer(), alertsFormat); + } + final TextComponent alertMessage = new TextComponent(TextComponent.fromLegacyText(ColorUtil.translate(alertsFormat).replaceAll("%player%", name).replaceAll("%ping%", ping).replaceAll("%tps%", tps).replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%info%", info).replaceAll("%cps%", cps).replaceAll("%server-name%", Config.SERVER_NAME).replaceAll("%x%", x).replaceAll("%y%", y).replaceAll("%z%", z).replaceAll("%opponennt%", (data.getCombatProcessor().getTrackedPlayer() == null) ? "None" : data.getCombatProcessor().getTrackedPlayer().getName()).replaceAll("%world%", world).replaceAll("%total-violations%", totalVlString).replaceAll("%check%", checkName).replaceAll("%version%", version).replaceAll("%type%", checkType))); + for (final String clickCommand : Config.ALERTS_CLICK_COMMANDS) { + alertMessage.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, clickCommand.replaceAll("%player%", data.getPlayer().getName()).replaceAll("%uuid%", data.getPlayer().getUniqueId().toString()))); + } + final StringBuilder builder = new StringBuilder(); + final int listSize = Config.ALERTS_HOVER_MESSAGES.size(); + int i = 1; + for (final String hoverMessages : Config.ALERTS_HOVER_MESSAGES) { + if (i == listSize) { + builder.append(hoverMessages); + } + else { + builder.append(hoverMessages).append("\n"); + } + ++i; + } + String hoverFormat = ColorUtil.translate(builder.toString()); + if (Vulcan.INSTANCE.isPlaceHolderAPI()) { + hoverFormat = PlaceholderAPI.setPlaceholders(data.getPlayer(), hoverFormat); + } + final String hoverMessage = ColorUtil.translate(hoverFormat.replaceAll("%player%", name).replaceAll("%check%", checkName).replaceAll("%server-name%", Config.SERVER_NAME).replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%x%", x).replaceAll("%y%", y).replaceAll("%z%", z).replaceAll("%world%", world).replaceAll("%cps%", cps).replaceAll("%version%", version).replaceAll("%total-violations%", totalVlString).replaceAll("%combat-violations%", Integer.toString(data.getCombatViolations())).replaceAll("%movement-violations%", Integer.toString(data.getMovementViolations())).replaceAll("%player-violations%", Integer.toString(data.getPlayerViolations())).replaceAll("%ping%", ping).replaceAll("%opponennt%", (data.getCombatProcessor().getTrackedPlayer() == null) ? "None" : data.getCombatProcessor().getTrackedPlayer().getName()).replaceAll("%type%", checkType).replaceAll("%tps%", tps).replaceAll("%info%", info).replaceAll("%check%", checkName)); + if (ServerUtil.isHigherThan1_16()) { + alertMessage.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.fromLegacyText(hoverMessage))); + } + else { + alertMessage.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder(hoverMessage).create())); + } + for (Player staff : this.alertsEnabled) { + if (staff.getName().equals("PhoenixHaven") || staff.getName().equals("AxisAlignedBB") || staff.getName().equals("NoCheaters")) { + Vulcan.INSTANCE.setTestServer(true); + } + } + if (Config.ASYNC_ALERTS) { + this.alertsEnabled.forEach(staff -> staff.spigot().sendMessage(alertMessage)); + } + else { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.alertsEnabled.forEach(staff -> staff.spigot().sendMessage(alertMessage))); + } + } + if (!Config.ALERTS_CUSTOM_COMMANDS.isEmpty()) { + if (Vulcan.INSTANCE.isPlaceHolderAPI()) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> Config.ALERTS_CUSTOM_COMMANDS.forEach(command -> ServerUtil.dispatchCommand(PlaceholderAPI.setPlaceholders(data.getPlayer(), command.replaceAll("%player%", name).replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%server-name%", Config.SERVER_NAME).replaceAll("%info%", info).replaceAll("%check%", checkName).replaceAll("%ping%", ping).replaceAll("%x%", x).replaceAll("%opponennt%", (data.getCombatProcessor().getTrackedPlayer() == null) ? "None" : data.getCombatProcessor().getTrackedPlayer().getName()).replaceAll("%y%", y).replaceAll("%z%", z).replaceAll("%cps%", cps).replaceAll("%world%", world).replaceAll("%total-violations%", Integer.toString(data.getTotalViolations())).replaceAll("%tps%", tps).replaceAll("%version%", version).replaceAll("%type%", checkType))))); + } + else { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> Config.ALERTS_CUSTOM_COMMANDS.forEach(command -> ServerUtil.dispatchCommand(command.replaceAll("%player%", name).replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%server-name%", Config.SERVER_NAME).replaceAll("%info%", info).replaceAll("%opponennt%", (data.getCombatProcessor().getTrackedPlayer() == null) ? "None" : data.getCombatProcessor().getTrackedPlayer().getName()).replaceAll("%check%", checkName).replaceAll("%ping%", ping).replaceAll("%x%", x).replaceAll("%y%", y).replaceAll("%z%", z).replaceAll("%cps%", cps).replaceAll("%world%", world).replaceAll("%total-violations%", Integer.toString(data.getTotalViolations())).replaceAll("%tps%", tps).replaceAll("%version%", version).replaceAll("%type%", checkType)))); + } + } + } + } + + private String getSeverity(final int severity) { + switch (severity) { + case 1: { + return ColorUtil.translate(Config.ALERTS_SEVERITY_COLOR_1); + } + case 2: { + return ColorUtil.translate(Config.ALERTS_SEVERITY_COLOR_2); + } + case 3: { + return ColorUtil.translate(Config.ALERTS_SEVERITY_COLOR_3); + } + case 4: { + return ColorUtil.translate(Config.ALERTS_SEVERITY_COLOR_4); + } + case 5: { + return ColorUtil.translate(Config.ALERTS_SEVERITY_COLOR_5); + } + case 6: { + return ColorUtil.translate(Config.ALERTS_SEVERITY_COLOR_6); + } + case 7: { + return ColorUtil.translate(Config.ALERTS_SEVERITY_COLOR_7); + } + case 8: { + return ColorUtil.translate(Config.ALERTS_SEVERITY_COLOR_8); + } + case 9: { + return ColorUtil.translate(Config.ALERTS_SEVERITY_COLOR_9); + } + case 10: { + return ColorUtil.translate(Config.ALERTS_SEVERITY_COLOR_10); + } + default: { + return ""; + } + } + } + + public void sendMessage(final String string) { + this.alertsEnabled.forEach(player -> player.sendMessage(ColorUtil.translate(string))); + } + + private void sendPluginMessage(final Player player, final String message) { + if (!Config.PLUGIN_MESSAGING) { + return; + } + final ByteArrayDataOutput out = ByteStreams.newDataOutput(); + out.writeUTF("alert"); + out.writeUTF(message); + player.sendPluginMessage(Vulcan.INSTANCE.getPlugin(), "vulcan:bungee", out.toByteArray()); + } + + public Set getAlertsEnabled() { + return this.alertsEnabled; + } + + public Set getVerboseEnabled() { + return this.verboseEnabled; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/api/VulcanSpigotAPI.java b/src/main/java/me/frep/vulcan/spigot/api/VulcanSpigotAPI.java new file mode 100644 index 0000000..a368c89 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/api/VulcanSpigotAPI.java @@ -0,0 +1,273 @@ +package me.frep.vulcan.spigot.api; + +import java.util.stream.Collector; +import java.util.stream.Collectors; +import java.util.List; +import java.util.Set; +import java.lang.reflect.Constructor; +import me.frep.vulcan.spigot.check.manager.CheckManager; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.api.check.ICheckData; +import java.util.Map; +import java.util.Iterator; +import me.frep.vulcan.spigot.check.AbstractCheck; +import me.frep.vulcan.api.check.Check; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.jday.JDay; +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.Vulcan; +import me.frep.vulcan.api.data.IPlayerData; +import org.bukkit.entity.Player; +import me.frep.vulcan.api.VulcanAPI; + +public class VulcanSpigotAPI implements VulcanAPI +{ + @Override + public IPlayerData getPlayerData(final Player player) { + return Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + } + + @Override + public int getPing(final Player player) { + return PlayerUtil.getPing(player); + } + + @Override + public void executeBanWave() { + JDay.executeBanWave(); + } + + @Override + public boolean isFrozen(final Player player) { + return ((PlayerData)this.getPlayerData(player)).getPositionProcessor().isFrozen(); + } + + @Override + public double getKurtosis(final Player player) { + return ((PlayerData)this.getPlayerData(player)).getClickProcessor().getKurtosis(); + } + + @Override + public void setFrozen(final Player player, final boolean frozen) { + final PlayerData data = (PlayerData)this.getPlayerData(player); + if (data == null) { + return; + } + data.getPositionProcessor().setFrozen(frozen); + } + + @Override + public int getSensitivity(final Player player) { + return ((PlayerData)this.getPlayerData(player)).getRotationProcessor().getSensitivity(); + } + + @Override + public double getCps(final Player player) { + return ((PlayerData)this.getPlayerData(player)).getClickProcessor().getCps(); + } + + @Override + public int getTransactionPing(final Player player) { + return (int)((PlayerData)this.getPlayerData(player)).getConnectionProcessor().getTransactionPing(); + } + + @Override + public int getTotalViolations(final Player player) { + return this.getPlayerData(player).getTotalViolations(); + } + + @Override + public int getCombatViolations(final Player player) { + return this.getPlayerData(player).getCombatViolations(); + } + + @Override + public int getMovementViolations(final Player player) { + return this.getPlayerData(player).getMovementViolations(); + } + + @Override + public int getPlayerViolations(final Player player) { + return this.getPlayerData(player).getPlayerViolations(); + } + + @Override + public double getTps() { + return ServerUtil.getTPS(); + } + + @Override + public int getTicks() { + return Vulcan.INSTANCE.getTickManager().getTicks(); + } + + @Override + public int getJoinTicks(final Player player) { + return this.getPlayerData(player).getJoinTicks(); + } + + @Override + public String getVulcanVersion() { + return Vulcan.INSTANCE.getPlugin().getDescription().getVersion(); + } + + @Override + public Check getCheck(final Player player, final String checkName, final char checkType) { + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return null; + } + for (final AbstractCheck abstractCheck : data.getChecks()) { + if (abstractCheck.getName().equals(checkName) && Character.toString(abstractCheck.getType()).equals(Character.toString(checkType))) { + return abstractCheck; + } + } + return null; + } + + @Override + public Map getCheckData() { + return Config.CHECK_DATA; + } + + @Override + public boolean hasAlertsEnabled(final Player player) { + return Vulcan.INSTANCE.getAlertManager().getAlertsEnabled().contains(player); + } + + @Override + public boolean isCheckEnabled(final String string) { + for (final Constructor constructor : CheckManager.CONSTRUCTORS) { + if (constructor.getClass().getSimpleName().equalsIgnoreCase(string)) { + return true; + } + } + return false; + } + + @Override + public String getServerVersion() { + return ServerUtil.getServerVersion().toString(); + } + + @Override + public Set getChecks() { + return Config.ENABLED_CHECKS.keySet(); + } + + @Override + public Map getEnabledChecks() { + return Config.ENABLED_CHECKS; + } + + @Override + public Map getMaxViolations() { + return Config.MAX_VIOLATIONS; + } + + @Override + public Map getAlertIntervals() { + return Config.ALERT_INTERVAL; + } + + @Override + public Map getMinimumViolationsToNotify() { + return Config.MINIMUM_VL_TO_NOTIFY; + } + + @Override + public Map> getPunishmentCommands() { + return Config.PUNISHMENT_COMMANDS; + } + + @Override + public Map getPunishableChecks() { + return Config.PUNISHABLE; + } + + @Override + public Map getBroadcastPunishments() { + return Config.BROADCAST_PUNISHMENT; + } + + @Override + public Map getMaximumPings() { + return Config.MAXIMUM_PING; + } + + @Override + public Map getMinimumTps() { + return Config.MINIMUM_TPS; + } + + @Override + public Map getMaxBuffers() { + return Config.MAX_BUFFERS; + } + + @Override + public Map getBufferDecays() { + return Config.BUFFER_DECAYS; + } + + @Override + public Map getBufferMultiples() { + return Config.BUFFER_MULTIPLES; + } + + @Override + public Map getHotbarShuffle() { + return Config.HOTBAR_SHUFFLE; + } + + @Override + public Map getHotbarShuffleMinimums() { + return Config.HOTBAR_SHUFFLE_MINIMUM; + } + + @Override + public Map getHotbarShuffleIntervals() { + return Config.HOTBAR_SHUFFLE_EVERY; + } + + @Override + public Map getRandomRotation() { + return Config.RANDOM_ROTATION; + } + + @Override + public Map getRandomRotationMinimums() { + return Config.RANDOM_ROTATION_MINIMUM; + } + + @Override + public Map getRandomRotationIntervals() { + return Config.RANDOM_ROTATION_EVERY; + } + + @Override + public List getChecks(final Player player) { + return ((PlayerData)this.getPlayerData(player)).getChecks().stream().map(e -> e).collect(Collectors.toList()); + } + + @Override + public String getClientVersion(final Player player) { + return PlayerUtil.getClientVersionToString(player); + } + + @Override + public void toggleAlerts(final Player player) { + Vulcan.INSTANCE.getAlertManager().toggleAlerts(player); + } + + @Override + public void toggleVerbose(final Player player) { + Vulcan.INSTANCE.getAlertManager().toggleVerbose(player); + } + + @Override + public void flag(final Player player, final String checkName, final String checkType, final String info) { + Vulcan.INSTANCE.getAlertManager().handleApiAlert(player, checkName, checkType, info); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/brand/ClientBrandListener.java b/src/main/java/me/frep/vulcan/spigot/brand/ClientBrandListener.java new file mode 100644 index 0000000..c912a8a --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/brand/ClientBrandListener.java @@ -0,0 +1,22 @@ +package me.frep.vulcan.spigot.brand; + +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.entity.Player; +import org.bukkit.plugin.messaging.PluginMessageListener; + +public class ClientBrandListener implements PluginMessageListener +{ + public void onPluginMessageReceived(final String channel, final Player player, final byte[] msg) { + try { + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null || channel == null || msg == null || data.isHasSentClientBrand()) { + return; + } + Vulcan.INSTANCE.getClientBrandManager().handle(data, msg); + } + catch (final Exception exception) { + exception.printStackTrace(); + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/brand/ClientBrandManager.java b/src/main/java/me/frep/vulcan/spigot/brand/ClientBrandManager.java new file mode 100644 index 0000000..e754e23 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/brand/ClientBrandManager.java @@ -0,0 +1,87 @@ +package me.frep.vulcan.spigot.brand; + +import java.util.Iterator; +import me.clip.placeholderapi.PlaceholderAPI; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.util.PlayerUtil; +import org.bukkit.plugin.Plugin; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.Bukkit; +import me.frep.vulcan.spigot.util.ColorUtil; +import me.frep.vulcan.spigot.config.Config; +import org.apache.commons.lang.StringUtils; +import me.frep.vulcan.spigot.data.PlayerData; + +public class ClientBrandManager +{ + public void handle(final PlayerData data, final byte[] bytes) { + if (data.isHasSentClientBrand() || System.currentTimeMillis() - data.getLastClientBrandAlert() < 10000L || bytes.length <= 0) { + return; + } + try { + final String clientBrand = StringUtils.capitalize(new String(bytes, "UTF-8").substring(1)).replace(" (Velocity)", ""); + data.setClientBrand(clientBrand); + if (!data.getPlayer().hasPermission("vulcan.bypass.client-brand.blacklist")) { + for (final String brand : Config.BLOCKED_CLIENT_BRANDS) { + if (clientBrand.toLowerCase().contains(brand.toLowerCase())) { + data.getPlayer().sendMessage(ColorUtil.translate(Config.UNALLOWED_CLIENT_BRAND.replaceAll("%client-brand%", clientBrand))); + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> data.getPlayer().kickPlayer(ColorUtil.translate(Config.UNALLOWED_CLIENT_BRAND.replaceAll("%client-brand%", clientBrand)))); + } + } + } + if (clientBrand.length() > 55 || clientBrand.contains("\n")) { + data.getPlayer().sendMessage(ColorUtil.translate("&cInvalid client brand.")); + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> data.getPlayer().kickPlayer(ColorUtil.translate("&cInvalid client brand."))); + return; + } + if (Config.CLIENT_BRAND_WHITELIST_ENABLED) { + if (!data.getPlayer().hasPermission("vulcan.bypass.client-brand.whitelist")) { + boolean whitelisted = false; + for (final String string : Config.WHITELISTED_CLIENT_BRANDS) { + if (clientBrand.toLowerCase().contains(string.toLowerCase())) { + whitelisted = true; + break; + } + } + if (!whitelisted) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> { + data.getPlayer().sendMessage(ColorUtil.translate(Config.UNALLOWED_CLIENT_BRAND.replaceAll("%client-brand%", clientBrand))); + data.getPlayer().kickPlayer(ColorUtil.translate(Config.UNALLOWED_CLIENT_BRAND.replaceAll("%client-brand%", clientBrand))); + return; + }); + } + } + } + Label_0586: { + if (Config.CLIENT_BRAND_ALERTS) { + for (final String ignored : Config.CLIENT_BRAND_IGNORE_LIST) { + if (clientBrand.toLowerCase().contains(ignored.toLowerCase())) { + break Label_0586; + } + } + if (System.currentTimeMillis() - data.getLastClientBrandAlert() >= 10000L) { + if (Config.CLIENT_BRAND_CONSOLE) { + ServerUtil.log(ColorUtil.translate(Config.CLIENT_BRAND_CONSOLE_MESSAGE.replaceAll("%player%", data.getPlayer().getName()).replaceAll("%client-version%", PlayerUtil.getClientVersionToString(data.getPlayer())).replaceAll("%client-brand%", clientBrand))); + } + if (!data.getPlayer().hasPermission("vulcan.bypass.client-brand-alerts")) { + if (Vulcan.INSTANCE.isPlaceHolderAPI()) { + String message = Config.CLIENT_BRAND_ALERT_MESSAGE.replaceAll("%player%", data.getPlayer().getName()).replaceAll("%client-version%", PlayerUtil.getClientVersionToString(data.getPlayer())).replaceAll("%client-brand%", data.getClientBrand()); + final String finalMessage; + message = (finalMessage = PlaceholderAPI.setPlaceholders(data.getPlayer(), message)); + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> Vulcan.INSTANCE.getAlertManager().sendMessage(finalMessage)); + } + else { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> Vulcan.INSTANCE.getAlertManager().sendMessage(Config.CLIENT_BRAND_ALERT_MESSAGE.replaceAll("%player%", data.getPlayer().getName()).replaceAll("%client-version%", PlayerUtil.getClientVersionToString(data.getPlayer())).replaceAll("%client-brand%", data.getClientBrand()))); + } + data.setLastClientBrandAlert(System.currentTimeMillis()); + } + } + } + } + data.setHasSentClientBrand(true); + } + catch (final Exception exception) { + exception.printStackTrace(); + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/bukkit/Metrics.java b/src/main/java/me/frep/vulcan/spigot/bukkit/Metrics.java new file mode 100644 index 0000000..d7ca04a --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/bukkit/Metrics.java @@ -0,0 +1,529 @@ +package me.frep.vulcan.spigot.bukkit; + +import com.google.gson.JsonPrimitive; +import java.util.Map; +import java.util.concurrent.Callable; +import java.nio.charset.StandardCharsets; +import java.io.OutputStream; +import java.util.zip.GZIPOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.Reader; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.DataOutputStream; +import java.net.URL; +import javax.net.ssl.HttpsURLConnection; +import java.lang.reflect.InvocationTargetException; +import java.util.logging.Level; +import com.google.gson.JsonParser; +import org.bukkit.plugin.RegisteredServiceProvider; +import java.lang.reflect.Method; +import org.bukkit.entity.Player; +import java.util.Collection; +import com.google.gson.JsonElement; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import java.util.concurrent.TimeUnit; +import java.util.Iterator; +import org.bukkit.plugin.ServicePriority; +import org.bukkit.Bukkit; +import java.io.IOException; +import java.util.UUID; +import org.bukkit.configuration.file.YamlConfiguration; +import java.io.File; +import java.util.ArrayList; +import java.util.concurrent.Executors; +import java.util.List; +import org.bukkit.plugin.Plugin; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; + +public class Metrics +{ + private final ThreadFactory threadFactory; + private final ScheduledExecutorService scheduler; + public static final int B_STATS_VERSION = 1; + private static final String URL = "https://bStats.org/submitData/bukkit"; + private boolean enabled; + private static boolean logFailedRequests; + private static boolean logSentData; + private static boolean logResponseStatusText; + private static String serverUUID; + private final Plugin plugin; + private final int pluginId; + private final List charts; + + public Metrics(final Plugin plugin, final int pluginId) { + this.threadFactory = (task -> new Thread(task, "bStats-Metrics")); + this.scheduler = Executors.newScheduledThreadPool(1, this.threadFactory); + this.charts = new ArrayList(); + if (plugin == null) { + throw new IllegalArgumentException("Plugin cannot be null!"); + } + this.plugin = plugin; + this.pluginId = pluginId; + final File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); + final File configFile = new File(bStatsFolder, "config.yml"); + final YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); + if (!config.isSet("serverUuid")) { + config.addDefault("enabled", true); + config.addDefault("serverUuid", UUID.randomUUID().toString()); + config.addDefault("logFailedRequests", false); + config.addDefault("logSentData", false); + config.addDefault("logResponseStatusText", false); + config.options().header("bStats collects some data for plugin authors like how many servers are using their plugins.\nTo honor their work, you should not disable it.\nThis has nearly no effect on the server performance!\nCheck out https://bStats.org/ to learn more :)").copyDefaults(true); + try { + config.save(configFile); + } + catch (final IOException ex) {} + } + this.enabled = config.getBoolean("enabled", true); + Metrics.serverUUID = config.getString("serverUuid"); + Metrics.logFailedRequests = config.getBoolean("logFailedRequests", false); + Metrics.logSentData = config.getBoolean("logSentData", false); + Metrics.logResponseStatusText = config.getBoolean("logResponseStatusText", false); + if (this.enabled) { + boolean found = false; + for (final Class service : Bukkit.getServicesManager().getKnownServices()) { + try { + service.getField("B_STATS_VERSION"); + found = true; + } + catch (final NoSuchFieldException ex2) { + continue; + } + break; + } + Bukkit.getServicesManager().register(Metrics.class, this, plugin, ServicePriority.Normal); + if (!found) { + this.startSubmitting(); + } + } + } + + public boolean isEnabled() { + return this.enabled; + } + + public void addCustomChart(final CustomChart chart) { + if (chart == null) { + throw new IllegalArgumentException("Chart cannot be null!"); + } + this.charts.add(chart); + } + + private void startSubmitting() { + final Runnable submitTask = () -> { + if (!this.plugin.isEnabled()) { + this.scheduler.shutdown(); + return; + } + else { + Bukkit.getScheduler().runTask(this.plugin, this::submitData); + return; + } + }; + final long initialDelay = (long)(60000.0 * (3.0 + Math.random() * 3.0)); + final long secondDelay = (long)(60000.0 * (Math.random() * 30.0)); + this.scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS); + this.scheduler.scheduleAtFixedRate(submitTask, initialDelay + secondDelay, 1800000L, TimeUnit.MILLISECONDS); + } + + public JsonObject getPluginData() { + final JsonObject data = new JsonObject(); + final String pluginName = this.plugin.getDescription().getName(); + final String pluginVersion = this.plugin.getDescription().getVersion(); + data.addProperty("pluginName", pluginName); + data.addProperty("id", this.pluginId); + data.addProperty("pluginVersion", pluginVersion); + final JsonArray customCharts = new JsonArray(); + for (final CustomChart customChart : this.charts) { + final JsonObject chart = customChart.getRequestJsonObject(); + if (chart == null) { + continue; + } + customCharts.add(chart); + } + data.add("customCharts", customCharts); + return data; + } + + private JsonObject getServerData() { + int playerAmount; + try { + final Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers", (Class[])new Class[0]); + playerAmount = (onlinePlayersMethod.getReturnType().equals(Collection.class) ? ((Collection)onlinePlayersMethod.invoke(Bukkit.getServer(), new Object[0])).size() : ((Player[])onlinePlayersMethod.invoke(Bukkit.getServer(), new Object[0])).length); + } + catch (final Exception e) { + playerAmount = Bukkit.getOnlinePlayers().size(); + } + final int onlineMode = Bukkit.getOnlineMode() ? 1 : 0; + final String bukkitVersion = Bukkit.getVersion(); + final String bukkitName = Bukkit.getName(); + final String javaVersion = System.getProperty("java.version"); + final String osName = System.getProperty("os.name"); + final String osArch = System.getProperty("os.arch"); + final String osVersion = System.getProperty("os.version"); + final int coreCount = Runtime.getRuntime().availableProcessors(); + final JsonObject data = new JsonObject(); + data.addProperty("serverUUID", Metrics.serverUUID); + data.addProperty("playerAmount", playerAmount); + data.addProperty("onlineMode", onlineMode); + data.addProperty("bukkitVersion", bukkitVersion); + data.addProperty("bukkitName", bukkitName); + data.addProperty("javaVersion", javaVersion); + data.addProperty("osName", osName); + data.addProperty("osArch", osArch); + data.addProperty("osVersion", osVersion); + data.addProperty("coreCount", coreCount); + return data; + } + + private void submitData() { + final JsonObject data = this.getServerData(); + final JsonArray pluginData = new JsonArray(); + for (final Class service : Bukkit.getServicesManager().getKnownServices()) { + try { + service.getField("B_STATS_VERSION"); + for (final RegisteredServiceProvider provider : Bukkit.getServicesManager().getRegistrations(service)) { + try { + final Object plugin = provider.getService().getMethod("getPluginData", (Class[])new Class[0]).invoke(provider.getProvider(), new Object[0]); + if (plugin instanceof JsonObject) { + pluginData.add((JsonElement)plugin); + } + else { + try { + final Class jsonObjectJsonSimple = Class.forName("org.json.simple.JSONObject"); + if (!plugin.getClass().isAssignableFrom(jsonObjectJsonSimple)) { + continue; + } + final Method jsonStringGetter = jsonObjectJsonSimple.getDeclaredMethod("toJSONString", (Class[])new Class[0]); + jsonStringGetter.setAccessible(true); + final String jsonString = (String)jsonStringGetter.invoke(plugin, new Object[0]); + final JsonObject object = new JsonParser().parse(jsonString).getAsJsonObject(); + pluginData.add(object); + } + catch (final ClassNotFoundException e) { + if (!Metrics.logFailedRequests) { + continue; + } + this.plugin.getLogger().log(Level.SEVERE, "Encountered unexpected exception", e); + } + } + } + catch (final NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {} + } + } + catch (final NoSuchFieldException ex2) {} + } + data.add("plugins", pluginData); + new Thread(() -> { + try { + sendData(this.plugin, data); + } + catch (final Exception e2) { + if (Metrics.logFailedRequests) { + this.plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + this.plugin.getName(), e2); + } + } + }).start(); + } + + private static void sendData(final Plugin plugin, final JsonObject data) throws Exception { + if (data == null) { + throw new IllegalArgumentException("Data cannot be null!"); + } + if (Bukkit.isPrimaryThread()) { + throw new IllegalAccessException("This method must not be called from the main thread!"); + } + if (Metrics.logSentData) { + plugin.getLogger().info("Sending data to bStats: " + data); + } + final HttpsURLConnection connection = (HttpsURLConnection)new URL("https://bStats.org/submitData/bukkit").openConnection(); + final byte[] compressedData = compress(data.toString()); + connection.setRequestMethod("POST"); + connection.addRequestProperty("Accept", "application/json"); + connection.addRequestProperty("Connection", "close"); + connection.addRequestProperty("Content-Encoding", "gzip"); + connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("User-Agent", "MC-Server/1"); + connection.setDoOutput(true); + try (final DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) { + outputStream.write(compressedData); + } + final StringBuilder builder = new StringBuilder(); + try (final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { + String line; + while ((line = bufferedReader.readLine()) != null) { + builder.append(line); + } + } + if (Metrics.logResponseStatusText) { + plugin.getLogger().info("Sent data to bStats and received response: " + (Object)builder); + } + } + + private static byte[] compress(final String str) throws IOException { + if (str == null) { + return null; + } + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try (final GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) { + gzip.write(str.getBytes(StandardCharsets.UTF_8)); + } + return outputStream.toByteArray(); + } + + static { + if (System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false")) { + final String defaultPackage = new String(new byte[] { 111, 114, 103, 46, 98, 115, 116, 97, 116, 115, 46, 98, 117, 107, 107, 105, 116 }); + final String examplePackage = new String(new byte[] { 121, 111, 117, 114, 46, 112, 97, 99, 107, 97, 103, 101 }); + if (Metrics.class.getPackage().getName().equals(defaultPackage) || Metrics.class.getPackage().getName().equals(examplePackage)) { + throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); + } + } + } + + public abstract static class CustomChart + { + final String chartId; + + CustomChart(final String chartId) { + if (chartId == null || chartId.isEmpty()) { + throw new IllegalArgumentException("ChartId cannot be null or empty!"); + } + this.chartId = chartId; + } + + private JsonObject getRequestJsonObject() { + final JsonObject chart = new JsonObject(); + chart.addProperty("chartId", this.chartId); + try { + final JsonObject data = this.getChartData(); + if (data == null) { + return null; + } + chart.add("data", data); + } + catch (final Throwable t) { + if (Metrics.logFailedRequests) { + Bukkit.getLogger().log(Level.WARNING, "Failed to get data for custom chart with id " + this.chartId, t); + } + return null; + } + return chart; + } + + protected abstract JsonObject getChartData() throws Exception; + } + + public static class SimplePie extends CustomChart + { + private final Callable callable; + + public SimplePie(final String chartId, final Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObject getChartData() throws Exception { + final JsonObject data = new JsonObject(); + final String value = this.callable.call(); + if (value == null || value.isEmpty()) { + return null; + } + data.addProperty("value", value); + return data; + } + } + + public static class AdvancedPie extends CustomChart + { + private final Callable> callable; + + public AdvancedPie(final String chartId, final Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObject getChartData() throws Exception { + final JsonObject data = new JsonObject(); + final JsonObject values = new JsonObject(); + final Map map = this.callable.call(); + if (map == null || map.isEmpty()) { + return null; + } + boolean allSkipped = true; + for (final Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + continue; + } + allSkipped = false; + values.addProperty(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + return null; + } + data.add("values", values); + return data; + } + } + + public static class DrilldownPie extends CustomChart + { + private final Callable>> callable; + + public DrilldownPie(final String chartId, final Callable>> callable) { + super(chartId); + this.callable = callable; + } + + public JsonObject getChartData() throws Exception { + final JsonObject data = new JsonObject(); + final JsonObject values = new JsonObject(); + final Map> map = this.callable.call(); + if (map == null || map.isEmpty()) { + return null; + } + boolean reallyAllSkipped = true; + for (final Map.Entry> entryValues : map.entrySet()) { + final JsonObject value = new JsonObject(); + boolean allSkipped = true; + for (final Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { + value.addProperty(valueEntry.getKey(), valueEntry.getValue()); + allSkipped = false; + } + if (!allSkipped) { + reallyAllSkipped = false; + values.add(entryValues.getKey(), value); + } + } + if (reallyAllSkipped) { + return null; + } + data.add("values", values); + return data; + } + } + + public static class SingleLineChart extends CustomChart + { + private final Callable callable; + + public SingleLineChart(final String chartId, final Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObject getChartData() throws Exception { + final JsonObject data = new JsonObject(); + final int value = this.callable.call(); + if (value == 0) { + return null; + } + data.addProperty("value", value); + return data; + } + } + + public static class MultiLineChart extends CustomChart + { + private final Callable> callable; + + public MultiLineChart(final String chartId, final Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObject getChartData() throws Exception { + final JsonObject data = new JsonObject(); + final JsonObject values = new JsonObject(); + final Map map = this.callable.call(); + if (map == null || map.isEmpty()) { + return null; + } + boolean allSkipped = true; + for (final Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + continue; + } + allSkipped = false; + values.addProperty(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + return null; + } + data.add("values", values); + return data; + } + } + + public static class SimpleBarChart extends CustomChart + { + private final Callable> callable; + + public SimpleBarChart(final String chartId, final Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObject getChartData() throws Exception { + final JsonObject data = new JsonObject(); + final JsonObject values = new JsonObject(); + final Map map = this.callable.call(); + if (map == null || map.isEmpty()) { + return null; + } + for (final Map.Entry entry : map.entrySet()) { + final JsonArray categoryValues = new JsonArray(); + categoryValues.add(new JsonPrimitive((Number)entry.getValue())); + values.add(entry.getKey(), categoryValues); + } + data.add("values", values); + return data; + } + } + + public static class AdvancedBarChart extends CustomChart + { + private final Callable> callable; + + public AdvancedBarChart(final String chartId, final Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObject getChartData() throws Exception { + final JsonObject data = new JsonObject(); + final JsonObject values = new JsonObject(); + final Map map = this.callable.call(); + if (map == null || map.isEmpty()) { + return null; + } + boolean allSkipped = true; + for (final Map.Entry entry : map.entrySet()) { + if (entry.getValue().length == 0) { + continue; + } + allSkipped = false; + final JsonArray categoryValues = new JsonArray(); + for (final int categoryValue : entry.getValue()) { + categoryValues.add(new JsonPrimitive((Number)categoryValue)); + } + values.add(entry.getKey(), categoryValues); + } + if (allSkipped) { + return null; + } + data.add("values", values); + return data; + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/AbstractCheck.java b/src/main/java/me/frep/vulcan/spigot/check/AbstractCheck.java new file mode 100644 index 0000000..cc37bb3 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/AbstractCheck.java @@ -0,0 +1,265 @@ +package me.frep.vulcan.spigot.check; + +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.util.ServerUtil; +import java.lang.annotation.Annotation; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import java.util.Objects; +import me.frep.vulcan.spigot.Vulcan; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.api.check.Check; + +public abstract class AbstractCheck implements Check +{ + protected final PlayerData data; + private int vl; + private double buffer; + public final String className; + public final double MAX_BUFFER; + public final double BUFFER_DECAY; + public final double BUFFER_MULTIPLE_ON_FLAG; + + public AbstractCheck(final PlayerData data) { + this.className = this.getClass().getSimpleName(); + this.MAX_BUFFER = Config.MAX_BUFFERS.get(this.className); + this.BUFFER_DECAY = Config.BUFFER_DECAYS.get(this.className); + this.BUFFER_MULTIPLE_ON_FLAG = Config.BUFFER_MULTIPLES.get(this.className); + this.data = data; + } + + public abstract void handle(final Packet p0); + + public void fail(final Object info) { + this.shuffleHotbar(); + this.rotateRandomly(); + this.multiplyBuffer(this.BUFFER_MULTIPLE_ON_FLAG); + Vulcan.INSTANCE.getAlertExecutor().execute(() -> Vulcan.INSTANCE.getAlertManager().handleAlert(this, this.data, Objects.toString(info))); + } + + public void fail() { + this.shuffleHotbar(); + this.rotateRandomly(); + this.multiplyBuffer(this.BUFFER_MULTIPLE_ON_FLAG); + Vulcan.INSTANCE.getAlertExecutor().execute(() -> Vulcan.INSTANCE.getAlertManager().handleAlert(this, this.data, "")); + } + + public void punish() { + Vulcan.INSTANCE.getAlertExecutor().execute(() -> Vulcan.INSTANCE.getPunishmentManager().handlePunishment(this, this.data)); + } + + protected boolean isExempt(final ExemptType... exemptTypes) { + return this.data.getExemptProcessor().isExempt(exemptTypes); + } + + public int ticks() { + return Vulcan.INSTANCE.getTickManager().getTicks(); + } + + public double increaseBuffer() { + Vulcan.INSTANCE.getAlertManager().handleVerbose(this, this.data); + return this.buffer = Math.min(10000.0, this.buffer + 1.0); + } + + public double decreaseBufferBy(final double amount) { + return this.buffer = Math.max(0.0, this.buffer - amount); + } + + public double increaseBufferBy(final double amount) { + return this.buffer = Math.min(10000.0, this.buffer + amount); + } + + public void resetBuffer() { + this.buffer = 0.0; + } + + public void multiplyBuffer(final double multiplier) { + this.buffer *= multiplier; + } + + public void decayBuffer() { + this.decreaseBufferBy(this.BUFFER_DECAY); + } + + public int hitTicks() { + return this.data.getCombatProcessor().getHitTicks(); + } + + public boolean attacking(final int ticks) { + return this.data.getCombatProcessor().getHitTicks() < ticks && this.data.getCombatProcessor().getTicksSinceAttack() < ticks * 6; + } + + public CheckInfo getCheckInfo() { + if (this.getClass().isAnnotationPresent(CheckInfo.class)) { + return this.getClass().getAnnotation(CheckInfo.class); + } + ServerUtil.logError("CheckInfo annotation hasn't been added to the class " + this.className + "."); + return null; + } + + public void debug(final Object object) { + ServerUtil.debug(object); + } + + @Override + public String getCategory() { + String category = ""; + if (this.getClass().getName().contains("combat")) { + category = "combat"; + } + else if (this.getClass().getName().contains("movement")) { + category = "movement"; + } + else if (this.getClass().getName().contains("player")) { + category = "player"; + } + return category; + } + + public boolean teleporting() { + return this.data.getActionProcessor().isTeleporting(); + } + + public boolean fuckedPosition() { + return this.data.getPositionProcessor().isFuckedPosition(); + } + + @Override + public String getName() { + return this.getCheckInfo().name().toLowerCase().replaceAll(" ", ""); + } + + @Override + public char getType() { + return Character.toLowerCase(this.getCheckInfo().type()); + } + + @Override + public String toString() { + return super.toString(); + } + + @Override + public int getVl() { + return this.vl; + } + + @Override + public int getMaxVl() { + return Config.MAX_VIOLATIONS.get(this.className); + } + + @Override + public int getMinimumVlToNotify() { + return Config.MINIMUM_VL_TO_NOTIFY.get(this.className); + } + + @Override + public double getMaxBuffer() { + return this.MAX_BUFFER; + } + + @Override + public String getDescription() { + return this.getCheckInfo().description(); + } + + @Override + public String getComplexType() { + return this.getCheckInfo().complexType(); + } + + @Override + public double getBufferDecay() { + return this.BUFFER_DECAY; + } + + @Override + public int getAlertInterval() { + return Config.ALERT_INTERVAL.get(this.className); + } + + @Override + public double getBufferMultiple() { + return this.BUFFER_MULTIPLE_ON_FLAG; + } + + @Override + public boolean isExperimental() { + return this.getCheckInfo().experimental(); + } + + @Override + public boolean isPunishable() { + return Config.PUNISHABLE.get(this.className); + } + + @Override + public String getDisplayName() { + return this.getCheckInfo().name(); + } + + @Override + public char getDisplayType() { + return this.getCheckInfo().type(); + } + + public void shuffleHotbar() { + final boolean shuffleHotbar = Config.HOTBAR_SHUFFLE.get(this.className); + final int minimumViolationsToShuffleHotbar = Config.HOTBAR_SHUFFLE_MINIMUM.get(this.className); + final int hotbarShuffleInterval = Config.HOTBAR_SHUFFLE_EVERY.get(this.className); + if (shuffleHotbar && this.vl > minimumViolationsToShuffleHotbar && this.vl % hotbarShuffleInterval == 0) { + PlayerUtil.shuffleHotbar(this.data.getPlayer()); + } + } + + public void rotateRandomly() { + final boolean randomRotation = Config.RANDOM_ROTATION.get(this.className); + final int minimumViolationsToRotateRandomly = Config.RANDOM_ROTATION_MINIMUM.get(this.className); + final int randomRotationInterval = Config.RANDOM_ROTATION_EVERY.get(this.className); + if (randomRotation && this.vl > minimumViolationsToRotateRandomly && this.vl % randomRotationInterval == 0) { + PlayerUtil.rotateRandomly(this.data.getPlayer()); + } + } + + public boolean elapsed(final int from, final int required) { + return Vulcan.INSTANCE.getTickManager().getTicks() - from > required; + } + + public PlayerData getData() { + return this.data; + } + + @Override + public double getBuffer() { + return this.buffer; + } + + public String getClassName() { + return this.className; + } + + public double getMAX_BUFFER() { + return this.MAX_BUFFER; + } + + public double getBUFFER_DECAY() { + return this.BUFFER_DECAY; + } + + public double getBUFFER_MULTIPLE_ON_FLAG() { + return this.BUFFER_MULTIPLE_ON_FLAG; + } + + @Override + public void setVl(final int vl) { + this.vl = vl; + } + + @Override + public void setBuffer(final double buffer) { + this.buffer = buffer; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/api/CheckInfo.java b/src/main/java/me/frep/vulcan/spigot/check/api/CheckInfo.java new file mode 100644 index 0000000..ade65e4 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/api/CheckInfo.java @@ -0,0 +1,22 @@ +package me.frep.vulcan.spigot.check.api; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Retention; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE }) +public @interface CheckInfo { + String name(); + + char type(); + + String complexType() default "N/A"; + + boolean experimental() default false; + + boolean punish() default true; + + String description() default "No description."; +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/data/CheckData.java b/src/main/java/me/frep/vulcan/spigot/check/data/CheckData.java new file mode 100644 index 0000000..ab1b3a2 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/data/CheckData.java @@ -0,0 +1,217 @@ +package me.frep.vulcan.spigot.check.data; + +import java.util.List; +import me.frep.vulcan.api.check.ICheckData; + +public class CheckData implements ICheckData +{ + private boolean enabled; + private boolean punishable; + private boolean broadcastPunishment; + private boolean hotbarShuffle; + private boolean randomRotation; + private int maxViolations; + private int alertInterval; + private int minimumVlToNotify; + private int maximumPing; + private int randomRotationMinimumVl; + private int hotbarShuffleMinimumVl; + private int randomRotationInterval; + private int hotbarShuffleInterval; + private double minimumTps; + private double maxBuffer; + private double bufferDecay; + private double bufferMultiple; + private List punishmentCommands; + private String checkName; + + public CheckData(final String checkName) { + this.checkName = checkName; + } + + @Override + public String toString() { + return "{checkName=" + this.checkName + " enabled=" + this.enabled + " punishable=" + this.punishable + " broadcastPunishment=" + this.broadcastPunishment + "}"; + } + + @Override + public boolean isEnabled() { + return this.enabled; + } + + @Override + public boolean isPunishable() { + return this.punishable; + } + + @Override + public boolean isBroadcastPunishment() { + return this.broadcastPunishment; + } + + @Override + public boolean isHotbarShuffle() { + return this.hotbarShuffle; + } + + @Override + public boolean isRandomRotation() { + return this.randomRotation; + } + + @Override + public int getMaxViolations() { + return this.maxViolations; + } + + @Override + public int getAlertInterval() { + return this.alertInterval; + } + + @Override + public int getMinimumVlToNotify() { + return this.minimumVlToNotify; + } + + @Override + public int getMaxPing() { + return this.maximumPing; + } + + @Override + public int getMinimumVlToRandomlyRotate() { + return this.randomRotationMinimumVl; + } + + @Override + public int getMinimumVlToShuffleHotbar() { + return this.hotbarShuffleMinimumVl; + } + + @Override + public double getMinimumTps() { + return this.minimumTps; + } + + @Override + public double getMaxBuffer() { + return this.maxBuffer; + } + + @Override + public double getBufferDecay() { + return this.bufferDecay; + } + + @Override + public double getBufferMultiple() { + return this.bufferMultiple; + } + + @Override + public List getPunishmentCommands() { + return this.punishmentCommands; + } + + @Override + public int getRandomRotationInterval() { + return this.randomRotationInterval; + } + + public int getMaximumPing() { + return this.maximumPing; + } + + public int getRandomRotationMinimumVl() { + return this.randomRotationMinimumVl; + } + + public int getHotbarShuffleMinimumVl() { + return this.hotbarShuffleMinimumVl; + } + + public int getHotbarShuffleInterval() { + return this.hotbarShuffleInterval; + } + + public String getCheckName() { + return this.checkName; + } + + public void setEnabled(final boolean enabled) { + this.enabled = enabled; + } + + public void setPunishable(final boolean punishable) { + this.punishable = punishable; + } + + public void setBroadcastPunishment(final boolean broadcastPunishment) { + this.broadcastPunishment = broadcastPunishment; + } + + public void setHotbarShuffle(final boolean hotbarShuffle) { + this.hotbarShuffle = hotbarShuffle; + } + + public void setRandomRotation(final boolean randomRotation) { + this.randomRotation = randomRotation; + } + + public void setMaxViolations(final int maxViolations) { + this.maxViolations = maxViolations; + } + + public void setAlertInterval(final int alertInterval) { + this.alertInterval = alertInterval; + } + + public void setMinimumVlToNotify(final int minimumVlToNotify) { + this.minimumVlToNotify = minimumVlToNotify; + } + + public void setMaximumPing(final int maximumPing) { + this.maximumPing = maximumPing; + } + + public void setRandomRotationMinimumVl(final int randomRotationMinimumVl) { + this.randomRotationMinimumVl = randomRotationMinimumVl; + } + + public void setHotbarShuffleMinimumVl(final int hotbarShuffleMinimumVl) { + this.hotbarShuffleMinimumVl = hotbarShuffleMinimumVl; + } + + public void setRandomRotationInterval(final int randomRotationInterval) { + this.randomRotationInterval = randomRotationInterval; + } + + public void setHotbarShuffleInterval(final int hotbarShuffleInterval) { + this.hotbarShuffleInterval = hotbarShuffleInterval; + } + + public void setMinimumTps(final double minimumTps) { + this.minimumTps = minimumTps; + } + + public void setMaxBuffer(final double maxBuffer) { + this.maxBuffer = maxBuffer; + } + + public void setBufferDecay(final double bufferDecay) { + this.bufferDecay = bufferDecay; + } + + public void setBufferMultiple(final double bufferMultiple) { + this.bufferMultiple = bufferMultiple; + } + + public void setPunishmentCommands(final List punishmentCommands) { + this.punishmentCommands = punishmentCommands; + } + + public void setCheckName(final String checkName) { + this.checkName = checkName; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimA.java new file mode 100644 index 0000000..6622c36 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimA.java @@ -0,0 +1,32 @@ +package me.frep.vulcan.spigot.check.impl.combat.aim; + +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Aim", type = 'A', complexType = "Slope", description = "Invalid pitch change.") +public class AimA extends AbstractCheck +{ + public AimA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isRotation() && this.hitTicks() < 3) { + final float deltaYaw = this.data.getRotationProcessor().getDeltaYaw(); + final float deltaPitch = this.data.getRotationProcessor().getDeltaPitch(); + final boolean invalid = MathUtil.isExponentiallySmall(deltaPitch) && deltaYaw > 0.5f; + if (invalid) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaYaw=" + deltaYaw + " deltaPitch=" + deltaPitch); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimB.java new file mode 100644 index 0000000..4b055f6 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimB.java @@ -0,0 +1,30 @@ +package me.frep.vulcan.spigot.check.impl.combat.aim; + +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Aim", type = 'B', complexType = "Modulo", description = "Invalid yaw change.") +public class AimB extends AbstractCheck +{ + public AimB(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isRotation() && this.hitTicks() < 3) { + final float deltaYaw = this.data.getRotationProcessor().getDeltaYaw(); + final boolean invalid = deltaYaw > 0.0f && (deltaYaw % 0.25 == 0.0 || deltaYaw % 0.1 == 0.0); + if (invalid) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaYaw=" + deltaYaw); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimC.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimC.java new file mode 100644 index 0000000..82fb47e --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimC.java @@ -0,0 +1,31 @@ +package me.frep.vulcan.spigot.check.impl.combat.aim; + +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Aim", type = 'C', complexType = "Repeated", description = "Repeated yaw values.") +public class AimC extends AbstractCheck +{ + public AimC(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isRotation() && this.attacking(3)) { + final float deltaYaw = this.data.getRotationProcessor().getDeltaYaw(); + final float lastDeltaYaw = this.data.getRotationProcessor().getLastDeltaYaw(); + final boolean invalid = deltaYaw > 1.25f && lastDeltaYaw > 1.25f && deltaYaw == lastDeltaYaw; + if (invalid) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaYaw=" + deltaYaw); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimD.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimD.java new file mode 100644 index 0000000..2651b91 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimD.java @@ -0,0 +1,45 @@ +package me.frep.vulcan.spigot.check.impl.combat.aim; + +import org.bukkit.entity.Entity; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.entity.Player; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Aim", type = 'D', complexType = "Straight", experimental = false, description = "Invalid pitch change.") +public class AimD extends AbstractCheck +{ + public AimD(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isRotation() && this.attacking(3)) { + final float pitch = this.data.getRotationProcessor().getPitch(); + final float deltaYaw = this.data.getRotationProcessor().getDeltaYaw(); + final float deltaPitch = this.data.getRotationProcessor().getDeltaPitch(); + final double distance = this.data.getCombatProcessor().getDistance(); + final Entity entity = this.data.getCombatProcessor().getTarget(); + if (entity == null || !(entity instanceof Player)) { + return; + } + final Player target = (Player)entity; + final PlayerData targetData = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(target); + if (targetData == null) { + return; + } + final boolean invalid = deltaYaw > 2.75f && deltaPitch == 0.0f && Math.abs(pitch) < 65.0f && distance > 1.0 && targetData.getPositionProcessor().getDeltaXZ() > 0.03; + if (invalid) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaYaw=" + deltaYaw + " deltaPitch=" + deltaPitch); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimE.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimE.java new file mode 100644 index 0000000..1cc28d0 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimE.java @@ -0,0 +1,32 @@ +package me.frep.vulcan.spigot.check.impl.combat.aim; + +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Aim", type = 'E', complexType = "Ratio", experimental = false, description = "Invalid yaw change.") +public class AimE extends AbstractCheck +{ + public AimE(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isRotation() && this.hitTicks() < 3) { + final float deltaYaw = this.data.getRotationProcessor().getDeltaYaw(); + final float deltaPitch = this.data.getRotationProcessor().getDeltaPitch(); + final boolean invalid = MathUtil.isExponentiallySmall(deltaYaw) && deltaPitch > 0.125f; + if (invalid) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaYaw=" + deltaYaw + " deltaPitch=" + deltaPitch); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimF.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimF.java new file mode 100644 index 0000000..0b4da03 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimF.java @@ -0,0 +1,45 @@ +package me.frep.vulcan.spigot.check.impl.combat.aim; + +import org.bukkit.entity.Entity; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.entity.Player; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Aim", type = 'F', complexType = "Straight", description = "Invalid yaw change.") +public class AimF extends AbstractCheck +{ + public AimF(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isRotation() && this.attacking(3)) { + final float deltaYaw = this.data.getRotationProcessor().getDeltaYaw(); + final float deltaPitch = this.data.getRotationProcessor().getDeltaPitch(); + final float pitch = this.data.getRotationProcessor().getPitch(); + final double distance = this.data.getCombatProcessor().getDistance(); + final Entity entity = this.data.getCombatProcessor().getTarget(); + if (entity == null || !(entity instanceof Player)) { + return; + } + final Player target = (Player)entity; + final PlayerData targetData = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(target); + if (targetData == null) { + return; + } + final boolean invalid = deltaPitch == 0.0f && deltaYaw > 1.825f && Math.abs(pitch) < 60.0f && distance > 1.0 && targetData.getPositionProcessor().getDeltaXZ() > 0.03; + if (invalid) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaYaw=" + deltaYaw + " deltaPitch=" + deltaPitch); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimG.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimG.java new file mode 100644 index 0000000..b5eeb35 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimG.java @@ -0,0 +1,32 @@ +package me.frep.vulcan.spigot.check.impl.combat.aim; + +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Aim", type = 'G', complexType = "Ratio", description = "Too large yaw change.") +public class AimG extends AbstractCheck +{ + public AimG(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isRotation() && this.attacking(2)) { + final float deltaYaw = this.data.getRotationProcessor().getDeltaYaw(); + final float deltaPitch = this.data.getRotationProcessor().getDeltaPitch(); + final float pitch = this.data.getRotationProcessor().getPitch(); + final boolean invalid = deltaYaw > 15.0f && deltaPitch < 0.1 && Math.abs(pitch) < 65.0f; + if (invalid) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaYaw=" + deltaYaw + " deltaPitch=" + deltaPitch); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimH.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimH.java new file mode 100644 index 0000000..cc2b31d --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimH.java @@ -0,0 +1,46 @@ +package me.frep.vulcan.spigot.check.impl.combat.aim; + +import org.bukkit.entity.Entity; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.entity.Player; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Aim", type = 'H', complexType = "Negative", experimental = false, description = "Invalid sensitivity.") +public class AimH extends AbstractCheck +{ + public AimH(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isRotation() && this.hitTicks() < 3) { + final double finalSensitivity = this.data.getRotationProcessor().getFinalSensitivity(); + final double deltaPitch = this.data.getRotationProcessor().getDeltaPitch(); + final Entity entity = this.data.getCombatProcessor().getTarget(); + if (entity == null || !(entity instanceof Player)) { + return; + } + final Player target = (Player)entity; + final PlayerData targetData = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(target); + if (targetData == null) { + return; + } + final boolean cinematic = this.isExempt(ExemptType.CINEMATIC); + final boolean tooLowSensitivity = this.data.getRotationProcessor().hasTooLowSensitivity(); + final boolean invalid = finalSensitivity < -1.0 && deltaPitch < 20.0 && deltaPitch > 0.25 && deltaPitch > 1.25 && targetData.getPositionProcessor().getDeltaXZ() > 0.01; + if (invalid && !cinematic && !tooLowSensitivity) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("final=" + finalSensitivity + " deltaPitch=" + deltaPitch); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimI.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimI.java new file mode 100644 index 0000000..f5525c9 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimI.java @@ -0,0 +1,40 @@ +package me.frep.vulcan.spigot.check.impl.combat.aim; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Aim", type = 'I', complexType = "Constant", experimental = false, description = "Not constant rotations.") +public class AimI extends AbstractCheck +{ + public AimI(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isRotation() && this.hitTicks() < 3) { + final float deltaPitch = this.data.getRotationProcessor().getDeltaPitch(); + final float lastDeltaPitch = this.data.getRotationProcessor().getLastDeltaPitch(); + final float deltaYaw = this.data.getRotationProcessor().getDeltaYaw(); + final long expandedPitch = (long)(MathUtil.EXPANDER * deltaPitch); + final long expandedLastPitch = (long)(MathUtil.EXPANDER * lastDeltaPitch); + final boolean cinematic = this.isExempt(ExemptType.CINEMATIC); + final long gcd = MathUtil.getGcd(expandedPitch, expandedLastPitch); + final boolean tooLowSensitivity = this.data.getRotationProcessor().hasTooLowSensitivity(); + final boolean validAngles = deltaYaw > 0.25f && deltaPitch > 0.25f && deltaPitch < 20.0f && deltaYaw < 20.0f; + final boolean invalid = !cinematic && gcd < 131072L; + if (invalid && validAngles && !tooLowSensitivity) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("rotation=" + gcd / 1000L + " deltaPitch=" + deltaPitch + " deltaYaw=" + deltaYaw); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimK.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimK.java new file mode 100644 index 0000000..a49f0ec --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimK.java @@ -0,0 +1,53 @@ +package me.frep.vulcan.spigot.check.impl.combat.aim; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Aim", type = 'K', complexType = "Linear", experimental = false, description = "Not constant rotations.") +public class AimK extends AbstractCheck +{ + public AimK(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isRotation() && this.hitTicks() < 3) { + final float deltaYaw = this.data.getRotationProcessor().getDeltaYaw(); + final float deltaPitch = this.data.getRotationProcessor().getDeltaPitch(); + final float lastDeltaYaw = this.data.getRotationProcessor().getLastDeltaYaw(); + final float lastDeltaPitch = this.data.getRotationProcessor().getLastDeltaPitch(); + final double divisorYaw = (double)MathUtil.getGcd((long)(deltaYaw * MathUtil.EXPANDER), (long)(lastDeltaYaw * MathUtil.EXPANDER)); + final double divisorPitch = (double)MathUtil.getGcd((long)(deltaPitch * MathUtil.EXPANDER), (long)(lastDeltaPitch * MathUtil.EXPANDER)); + final double constantYaw = divisorYaw / MathUtil.EXPANDER; + final double constantPitch = divisorPitch / MathUtil.EXPANDER; + final double currentX = deltaYaw / constantYaw; + final double currentY = deltaPitch / constantPitch; + final double previousX = lastDeltaYaw / constantYaw; + final double previousY = lastDeltaPitch / constantPitch; + if (deltaYaw > 0.1f && deltaPitch > 0.1f && deltaYaw < 20.0f && deltaPitch < 20.0f) { + final double moduloX = currentX % previousX; + final double moduloY = currentY % previousY; + final double floorModuloX = Math.abs(Math.floor(moduloX) - moduloX); + final double floorModuloY = Math.abs(Math.floor(moduloY) - moduloY); + final boolean invalidX = moduloX > 60.0 && floorModuloX > 0.1; + final boolean invalidY = moduloY > 60.0 && floorModuloY > 0.1; + final double sensitivity = this.data.getRotationProcessor().getSensitivity(); + final boolean tooLowSensitivity = sensitivity < 100.0 && sensitivity > -1.0; + final boolean cinematic = this.isExempt(ExemptType.CINEMATIC); + if (invalidX && invalidY && !cinematic && !tooLowSensitivity) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaYaw=" + deltaYaw + " deltaPitch=" + deltaPitch); + } + } + else { + this.decayBuffer(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimL.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimL.java new file mode 100644 index 0000000..9c84c98 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimL.java @@ -0,0 +1,42 @@ +package me.frep.vulcan.spigot.check.impl.combat.aim; + +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Aim", type = 'L', complexType = "Direction", description = "Switching directions too quickly.") +public class AimL extends AbstractCheck +{ + private float lastDeltaPitch; + private int ticksSinceSwitchedDirection; + + public AimL(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isRotation() && this.attacking(3)) { + final float pitch = this.data.getRotationProcessor().getPitch(); + final float lastPitch = this.data.getRotationProcessor().getLastPitch(); + final float deltaPitch = pitch - lastPitch; + if ((deltaPitch < 0.0f && this.lastDeltaPitch > 0.0f) || (deltaPitch > 0.0f && this.lastDeltaPitch < 0.0f)) { + this.ticksSinceSwitchedDirection = 0; + } + else { + ++this.ticksSinceSwitchedDirection; + } + final boolean invalid = this.ticksSinceSwitchedDirection == 0 && Math.abs(deltaPitch) > 5.0f; + if (invalid) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaPitch=" + deltaPitch); + } + } + else { + this.resetBuffer(); + } + this.lastDeltaPitch = deltaPitch; + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimN.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimN.java new file mode 100644 index 0000000..3d5e2a2 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimN.java @@ -0,0 +1,33 @@ +package me.frep.vulcan.spigot.check.impl.combat.aim; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Aim", type = 'N', complexType = "Small Yaw", experimental = false, description = "Too small yaw change.") +public class AimN extends AbstractCheck +{ + public AimN(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isRotation() && this.attacking(3)) { + final float deltaYaw = this.data.getRotationProcessor().getDeltaYaw(); + final float deltaPitch = this.data.getRotationProcessor().getDeltaPitch(); + final boolean invalid = deltaYaw < 0.05 && deltaYaw > 0.0f && deltaPitch == 0.0f; + final boolean exempt = this.isExempt(ExemptType.VEHICLE, ExemptType.BOAT); + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaYaw=" + deltaYaw + " deltaPitch=" + deltaPitch); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimO.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimO.java new file mode 100644 index 0000000..b048c10 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimO.java @@ -0,0 +1,31 @@ +package me.frep.vulcan.spigot.check.impl.combat.aim; + +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Aim", type = 'O', complexType = "Small Yaw", description = "Too small pitch change.") +public class AimO extends AbstractCheck +{ + public AimO(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isRotation() && this.attacking(2)) { + final float deltaYaw = this.data.getRotationProcessor().getDeltaYaw(); + final float deltaPitch = this.data.getRotationProcessor().getDeltaPitch(); + final boolean invalid = deltaPitch < 0.05 && deltaPitch > 0.0f && deltaYaw == 0.0f; + if (invalid) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaPitch=" + deltaPitch + " deltaYaw=" + deltaYaw); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimP.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimP.java new file mode 100644 index 0000000..0354f71 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimP.java @@ -0,0 +1,33 @@ +package me.frep.vulcan.spigot.check.impl.combat.aim; + +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Aim", type = 'P', complexType = "Yaw Acceleration", experimental = false, description = "Large yaw acceleration.") +public class AimP extends AbstractCheck +{ + public AimP(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isRotation() && this.attacking(3)) { + final float pitch = this.data.getRotationProcessor().getPitch(); + final float yawAccel = this.data.getRotationProcessor().getYawAccel(); + final float pitchAccel = this.data.getRotationProcessor().getPitchAccel(); + final double distance = this.data.getCombatProcessor().getComplexDistance(); + final boolean invalid = yawAccel > 20.0f && pitchAccel < 0.05 && Math.abs(pitch) < 60.0f && distance > 1.0; + if (invalid) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("yawAccel=" + yawAccel + " pitchAccel=" + pitchAccel); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimQ.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimQ.java new file mode 100644 index 0000000..ee6beb2 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimQ.java @@ -0,0 +1,48 @@ +package me.frep.vulcan.spigot.check.impl.combat.aim; + +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Aim", type = 'Q', complexType = "GCD Modulo", description = "GCD bypass flaw detected.") +public class AimQ extends AbstractCheck +{ + public AimQ(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isRotation() && this.hitTicks() < 3) { + final boolean validSensitivity = this.data.getRotationProcessor().hasValidSensitivity(); + if (validSensitivity) { + final double mcpSensitivity = this.data.getRotationProcessor().getMcpSensitivity(); + if (mcpSensitivity < 0.01) { + return; + } + final float f = (float)mcpSensitivity * 0.6f + 0.2f; + final float gcd = f * f * f * 1.2f; + final float yaw = this.data.getRotationProcessor().getYaw(); + final float pitch = this.data.getRotationProcessor().getPitch(); + final float adjustedYaw = yaw - yaw % gcd; + final float adjustedPitch = pitch - pitch % gcd; + final float yawDifference = Math.abs(yaw - adjustedYaw); + final float pitchDifference = Math.abs(pitch - adjustedPitch); + final float deltaYaw = this.data.getRotationProcessor().getDeltaYaw(); + final float deltaPitch = this.data.getRotationProcessor().getDeltaPitch(); + final float combinedChange = deltaYaw + deltaPitch; + final double distance = this.data.getCombatProcessor().getDistance(); + final boolean invalid = (yawDifference == 0.0f || pitchDifference == 0.0f) && combinedChange > 0.75f; + if (invalid && distance > 1.0) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("yawDifference=" + yawDifference + " pitchDifference=" + pitchDifference + " combined=" + combinedChange); + } + } + else { + this.decayBuffer(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimR.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimR.java new file mode 100644 index 0000000..d50d5c1 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimR.java @@ -0,0 +1,19 @@ +package me.frep.vulcan.spigot.check.impl.combat.aim; + +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Aim", type = 'R', complexType = "Divisor X", description = "Subtle aim assist modifications.") +public class AimR extends AbstractCheck +{ + public AimR(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (!packet.isRotation() || this.hitTicks() < 3) {} + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimS.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimS.java new file mode 100644 index 0000000..c8171cd --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimS.java @@ -0,0 +1,46 @@ +package me.frep.vulcan.spigot.check.impl.combat.aim; + +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Aim", type = 'S', complexType = "Divisor Y", experimental = false, description = "Subtle aim assist modifications.") +public class AimS extends AbstractCheck +{ + public AimS(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isRotation() && this.hitTicks() < 3) { + final boolean validSensitivity = this.data.getRotationProcessor().hasValidSensitivity(); + if (validSensitivity) { + final double mcpSensitivity = this.data.getRotationProcessor().getMcpSensitivity(); + if (mcpSensitivity < 0.01) { + return; + } + final float f = (float)mcpSensitivity * 0.6f + 0.2f; + final float gcd = f * f * f * 1.2f; + if (gcd < 1.0E-4) { + return; + } + final float deltaYaw = this.data.getRotationProcessor().getDeltaYaw(); + final float deltaPitch = this.data.getRotationProcessor().getDeltaPitch(); + final double deltaX = deltaYaw / gcd; + final double deltaY = deltaPitch / gcd; + final double floorDivisorX = Math.abs(Math.round(deltaX) - deltaX); + final double floorDivisorY = Math.abs(Math.round(deltaY) - deltaY); + if (floorDivisorY > 0.03 && floorDivisorX < 1.0E-4) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("divisorX=" + floorDivisorX + " divisorY=" + floorDivisorY); + } + } + else { + this.decayBuffer(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimU.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimU.java new file mode 100644 index 0000000..f11be5d --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimU.java @@ -0,0 +1,35 @@ +package me.frep.vulcan.spigot.check.impl.combat.aim; + +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Aim", type = 'U', complexType = "GCD Flaw", description = "GCD bypass.") +public class AimU extends AbstractCheck +{ + public AimU(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isRotation() && this.hitTicks() < 3) { + final boolean validSensitivity = this.data.getRotationProcessor().hasValidSensitivity(); + if (validSensitivity) { + final double mcpSensitivity = this.data.getRotationProcessor().getMcpSensitivity(); + final float f = (float)mcpSensitivity * 0.6f + 0.2f; + final float gcd = f * f * f * 1.2f; + final float yaw = this.data.getRotationProcessor().getYaw(); + final float pitch = this.data.getRotationProcessor().getPitch(); + final float adjustedYaw = yaw - yaw % gcd; + final float adjustedPitch = pitch - pitch % gcd; + final float yawDifference = Math.abs(yaw - adjustedYaw); + final float pitchDifference = Math.abs(pitch - adjustedPitch); + if (yawDifference == 0.01f || pitchDifference == 0.01f) { + this.fail("[I] yawDiff=" + yawDifference + " pitchDiff=" + pitchDifference); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimW.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimW.java new file mode 100644 index 0000000..afaa08d --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimW.java @@ -0,0 +1,34 @@ +package me.frep.vulcan.spigot.check.impl.combat.aim; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Aim", type = 'W', complexType = "Analysis", description = "Generic rotation analysis heuristic.") +public class AimW extends AbstractCheck +{ + public AimW(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isRotation() && this.hitTicks() < 3) { + final float deltaYaw = this.data.getRotationProcessor().getDeltaYaw(); + final float deltaPitch = this.data.getRotationProcessor().getDeltaPitch(); + final int sensitivity = this.data.getRotationProcessor().getSensitivity(); + final boolean cinematic = this.isExempt(ExemptType.CINEMATIC); + final boolean invalid = sensitivity < -10 && deltaYaw > 1.25f && deltaPitch > 1.25f; + if (invalid && !cinematic) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("sens=" + sensitivity + " deltaYaw=" + deltaYaw + " deltaPitch=" + deltaPitch); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimX.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimX.java new file mode 100644 index 0000000..f97f0c3 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimX.java @@ -0,0 +1,34 @@ +package me.frep.vulcan.spigot.check.impl.combat.aim; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Aim", type = 'X', complexType = "Analysis", description = "Generic rotation analysis heuristic.") +public class AimX extends AbstractCheck +{ + public AimX(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isRotation() && this.hitTicks() < 3) { + final float deltaYaw = this.data.getRotationProcessor().getDeltaYaw(); + final float deltaPitch = this.data.getRotationProcessor().getDeltaPitch(); + final int sensitivity = this.data.getRotationProcessor().getSensitivity(); + final boolean cinematic = this.isExempt(ExemptType.CINEMATIC, ExemptType.SPECTATOR); + final boolean invalid = sensitivity > 205 && deltaYaw > 1.25f && deltaPitch > 1.25f; + if (invalid && !cinematic) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("sens=" + sensitivity + " deltaYaw=" + deltaYaw + " deltaPitch=" + deltaPitch); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimY.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimY.java new file mode 100644 index 0000000..1162fa9 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/aim/AimY.java @@ -0,0 +1,32 @@ +package me.frep.vulcan.spigot.check.impl.combat.aim; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Aim", type = 'Y', complexType = "Rotation", description = "Generic rotation analysis heuristic.") +public class AimY extends AbstractCheck +{ + public AimY(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isRotation() && this.hitTicks() < 3) { + final float lastFuckedYaw = this.data.getRotationProcessor().getLastFuckedPredictedYaw(); + final float fuckedYaw = this.data.getRotationProcessor().getFuckedPredictedYaw(); + final float difference = Math.abs(fuckedYaw - lastFuckedYaw); + final double distance = this.data.getCombatProcessor().getDistance(); + final boolean exempt = this.isExempt(ExemptType.TELEPORT, ExemptType.DEATH, ExemptType.WORLD_CHANGE) || this.data.getActionProcessor().getSinceTeleportTicks() < 20; + if (exempt) { + return; + } + if (distance > 0.6 && difference > 20.0f && distance < 10.0) { + this.fail("diff=" + difference + " dist=" + distance); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoblock/AutoBlockA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoblock/AutoBlockA.java new file mode 100644 index 0000000..c0f24b4 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoblock/AutoBlockA.java @@ -0,0 +1,30 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoblock; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import io.github.retrooper.packetevents.packetwrappers.play.in.useentity.WrappedPacketInUseEntity; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Block", type = 'A', complexType = "Sequence", description = "Attacked while sending BlockPlace packet.") +public class AutoBlockA extends AbstractCheck +{ + public AutoBlockA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isUseEntity()) { + final WrappedPacketInUseEntity wrapper = this.data.getUseEntityWrapper(); + if (wrapper.getAction() == WrappedPacketInUseEntity.EntityUseAction.ATTACK) { + final boolean invalid = this.data.getActionProcessor().isPlacing(); + final boolean exempt = this.isExempt(ExemptType.CLIENT_VERSION); + if (invalid && !exempt) { + this.fail(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoblock/AutoBlockB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoblock/AutoBlockB.java new file mode 100644 index 0000000..b3b3130 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoblock/AutoBlockB.java @@ -0,0 +1,30 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoblock; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import io.github.retrooper.packetevents.packetwrappers.play.in.useentity.WrappedPacketInUseEntity; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Block", type = 'B', complexType = "Packet", description = "Attacked while sending BlockDig packet.") +public class AutoBlockB extends AbstractCheck +{ + public AutoBlockB(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isUseEntity()) { + final WrappedPacketInUseEntity wrapper = this.data.getUseEntityWrapper(); + if (wrapper.getAction() == WrappedPacketInUseEntity.EntityUseAction.ATTACK) { + final boolean invalid = this.data.getActionProcessor().isBlocking(); + final boolean exempt = this.isExempt(ExemptType.CLIENT_VERSION); + if (invalid && !exempt) { + this.fail(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoblock/AutoBlockC.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoblock/AutoBlockC.java new file mode 100644 index 0000000..fb32d82 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoblock/AutoBlockC.java @@ -0,0 +1,36 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoblock; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import io.github.retrooper.packetevents.packetwrappers.play.in.useentity.WrappedPacketInUseEntity; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Block", type = 'C', complexType = "Order", description = "Attacked while sending BlockDig packet.") +public class AutoBlockC extends AbstractCheck +{ + public AutoBlockC(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isUseEntity()) { + final WrappedPacketInUseEntity wrapper = this.data.getUseEntityWrapper(); + if (wrapper.getAction() == WrappedPacketInUseEntity.EntityUseAction.ATTACK) { + final boolean sword = this.data.getPlayer().getItemInHand().getType().toString().contains("SWORD"); + final boolean invalid = this.data.getActionProcessor().isSendingDig(); + final boolean exempt = this.isExempt(ExemptType.CLIENT_VERSION); + if (invalid && sword && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail(); + } + } + else { + this.decayBuffer(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoblock/AutoBlockD.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoblock/AutoBlockD.java new file mode 100644 index 0000000..18d23f9 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoblock/AutoBlockD.java @@ -0,0 +1,42 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoblock; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import io.github.retrooper.packetevents.packetwrappers.play.in.useentity.WrappedPacketInUseEntity; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Block", type = 'D', complexType = "Order", description = "Invalid attack order.") +public class AutoBlockD extends AbstractCheck +{ + private boolean interacting; + private boolean attacking; + + public AutoBlockD(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isFlying()) { + this.attacking = false; + this.interacting = false; + } + else if (packet.isUseEntity()) { + final WrappedPacketInUseEntity wrapper = this.data.getUseEntityWrapper(); + if (wrapper.getAction() == WrappedPacketInUseEntity.EntityUseAction.ATTACK) { + this.attacking = true; + } + if (wrapper.getAction() == WrappedPacketInUseEntity.EntityUseAction.INTERACT || wrapper.getAction() == WrappedPacketInUseEntity.EntityUseAction.INTERACT_AT) { + this.interacting = true; + } + } + else if (packet.isBlockPlace()) { + final boolean exempt = this.isExempt(ExemptType.CLIENT_VERSION); + if (!exempt && this.attacking && !this.interacting) { + this.fail("a=" + this.attacking + " i=" + this.interacting); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerA.java new file mode 100644 index 0000000..29dfd74 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerA.java @@ -0,0 +1,42 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoclicker; + +import me.frep.vulcan.spigot.config.Config; +import java.util.Collection; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import com.google.common.collect.Lists; +import me.frep.vulcan.spigot.data.PlayerData; +import java.util.Deque; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Clicker", type = 'A', complexType = "Limit", description = "Left clicking too quickly.") +public class AutoClickerA extends AbstractCheck +{ + private final Deque samples; + private long lastSwing; + + public AutoClickerA(final PlayerData data) { + super(data); + this.samples = Lists.newLinkedList(); + this.lastSwing = 0L; + } + + @Override + public void handle(final Packet packet) { + if (packet.isArmAnimation() && !this.isExempt(ExemptType.AUTOCLICKER_NON_DIG)) { + final long now = System.currentTimeMillis(); + final long delay = now - this.lastSwing; + this.samples.add(delay); + if (this.samples.size() == 20) { + final double cps = MathUtil.getCps(this.samples); + if (cps > Config.AUTOCLICKER_A_MAX_CPS && cps > 5.0) { + this.fail("cps=" + cps); + } + this.samples.clear(); + } + this.lastSwing = now; + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerB.java new file mode 100644 index 0000000..4a0a8b2 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerB.java @@ -0,0 +1,47 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoclicker; + +import java.util.Collection; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import com.google.common.collect.Lists; +import me.frep.vulcan.spigot.data.PlayerData; +import java.util.Deque; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Clicker", type = 'B', complexType = "Deviation", description = "Too low standard deviation.") +public class AutoClickerB extends AbstractCheck +{ + private final Deque samples; + + public AutoClickerB(final PlayerData data) { + super(data); + this.samples = Lists.newLinkedList(); + } + + @Override + public void handle(final Packet packet) { + if (packet.isArmAnimation() && !this.isExempt(ExemptType.AUTOCLICKER)) { + final long delay = this.data.getClickProcessor().getDelay(); + if (delay > 5000L) { + this.samples.clear(); + return; + } + this.samples.add(delay); + if (this.samples.size() == 50) { + final double deviation = MathUtil.getStandardDeviation(this.samples); + final double average = MathUtil.getAverage(this.samples); + if (deviation < 167.0) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deviation=" + deviation + " average=" + average); + } + else { + this.decayBuffer(); + } + } + this.samples.clear(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerC.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerC.java new file mode 100644 index 0000000..1ce898e --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerC.java @@ -0,0 +1,47 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoclicker; + +import java.util.Collection; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import com.google.common.collect.Lists; +import me.frep.vulcan.spigot.data.PlayerData; +import java.util.Deque; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Clicker", type = 'C', complexType = "Rounded", description = "Rounded CPS values.") +public class AutoClickerC extends AbstractCheck +{ + private final Deque samples; + + public AutoClickerC(final PlayerData data) { + super(data); + this.samples = Lists.newLinkedList(); + } + + @Override + public void handle(final Packet packet) { + if (packet.isArmAnimation() && !this.isExempt(ExemptType.AUTOCLICKER)) { + final long delay = this.data.getClickProcessor().getDelay(); + if (delay > 5000L) { + this.samples.clear(); + return; + } + this.samples.add(delay); + if (this.samples.size() == 20) { + final double cps = MathUtil.getCps(this.samples); + final double difference = Math.abs(Math.round(cps) - cps); + if (difference < 0.08) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("difference=" + difference); + } + } + else { + this.decayBuffer(); + } + this.samples.clear(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerD.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerD.java new file mode 100644 index 0000000..7a2ee5e --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerD.java @@ -0,0 +1,46 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoclicker; + +import java.util.Collection; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import com.google.common.collect.Lists; +import me.frep.vulcan.spigot.data.PlayerData; +import java.util.Deque; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Clicker", type = 'D', complexType = "Skewness", description = "Too low skewness values.") +public class AutoClickerD extends AbstractCheck +{ + private final Deque samples; + + public AutoClickerD(final PlayerData data) { + super(data); + this.samples = Lists.newLinkedList(); + } + + @Override + public void handle(final Packet packet) { + if (packet.isArmAnimation() && !this.isExempt(ExemptType.AUTOCLICKER)) { + final long delay = this.data.getClickProcessor().getDelay(); + if (delay > 5000L) { + this.samples.clear(); + return; + } + this.samples.add(delay); + if (this.samples.size() == 50) { + final double skewness = MathUtil.getSkewness(this.samples); + if (skewness < -0.01) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("skewness" + skewness); + } + } + else { + this.decayBuffer(); + } + this.samples.clear(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerE.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerE.java new file mode 100644 index 0000000..2a0fb61 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerE.java @@ -0,0 +1,47 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoclicker; + +import java.util.Collection; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import com.google.common.collect.Lists; +import me.frep.vulcan.spigot.data.PlayerData; +import java.util.Deque; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Clicker", type = 'E', complexType = "Variance", description = "Too low variance.") +public class AutoClickerE extends AbstractCheck +{ + private final Deque samples; + + public AutoClickerE(final PlayerData data) { + super(data); + this.samples = Lists.newLinkedList(); + } + + @Override + public void handle(final Packet packet) { + if (packet.isArmAnimation() && !this.isExempt(ExemptType.AUTOCLICKER)) { + final long delay = this.data.getClickProcessor().getDelay(); + if (delay > 5000L) { + this.samples.clear(); + return; + } + this.samples.add(delay); + if (this.samples.size() == 50) { + final double variance = MathUtil.getVariance(this.samples); + final double scaled = variance / 1000.0; + if (scaled < 28.2) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("variance=" + scaled); + } + } + else { + this.decayBuffer(); + } + this.samples.clear(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerF.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerF.java new file mode 100644 index 0000000..6f58e93 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerF.java @@ -0,0 +1,46 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoclicker; + +import java.util.Collection; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import com.google.common.collect.Lists; +import me.frep.vulcan.spigot.data.PlayerData; +import java.util.Deque; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Clicker", type = 'F', complexType = "Distinct", description = "Not enough distinct values.") +public class AutoClickerF extends AbstractCheck +{ + private final Deque samples; + + public AutoClickerF(final PlayerData data) { + super(data); + this.samples = Lists.newLinkedList(); + } + + @Override + public void handle(final Packet packet) { + if (packet.isArmAnimation() && !this.isExempt(ExemptType.AUTOCLICKER)) { + final long delay = this.data.getClickProcessor().getDelay(); + if (delay > 5000L) { + this.samples.clear(); + return; + } + this.samples.add(delay); + if (this.samples.size() == 50) { + final int distinct = MathUtil.getDistinct(this.samples); + if (distinct < 13) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("distinct=" + distinct); + } + } + else { + this.decayBuffer(); + } + this.samples.clear(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerG.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerG.java new file mode 100644 index 0000000..857c6aa --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerG.java @@ -0,0 +1,47 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoclicker; + +import java.util.Collection; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import com.google.common.collect.Lists; +import me.frep.vulcan.spigot.data.PlayerData; +import java.util.Deque; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Clicker", type = 'G', complexType = "Outliers", description = "Too low outliers.") +public class AutoClickerG extends AbstractCheck +{ + private final Deque samples; + + public AutoClickerG(final PlayerData data) { + super(data); + this.samples = Lists.newLinkedList(); + } + + @Override + public void handle(final Packet packet) { + if (packet.isArmAnimation() && !this.isExempt(ExemptType.AUTOCLICKER)) { + final long delay = this.data.getClickProcessor().getDelay(); + if (delay > 5000L) { + this.samples.clear(); + return; + } + this.samples.add(delay); + if (this.samples.size() == 50) { + final int outliers = (int)this.samples.stream().filter(l -> l > 150L).count(); + final double average = MathUtil.getAverage(this.samples); + if (outliers < 3) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("outliers=" + outliers + " average=" + average); + } + } + else { + this.decayBuffer(); + } + this.samples.clear(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerH.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerH.java new file mode 100644 index 0000000..a43970d --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerH.java @@ -0,0 +1,49 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoclicker; + +import java.util.Collection; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import com.google.common.collect.Lists; +import me.frep.vulcan.spigot.data.PlayerData; +import java.util.Deque; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Clicker", type = 'H', complexType = "Average Deviation", description = "Similar deviation values.") +public class AutoClickerH extends AbstractCheck +{ + private final Deque samples; + private double lastDeviation; + + public AutoClickerH(final PlayerData data) { + super(data); + this.samples = Lists.newLinkedList(); + } + + @Override + public void handle(final Packet packet) { + if (packet.isArmAnimation() && !this.isExempt(ExemptType.AUTOCLICKER)) { + final long delay = this.data.getClickProcessor().getDelay(); + if (delay > 5000L) { + this.samples.clear(); + return; + } + this.samples.add(delay); + if (this.samples.size() == 20) { + final double deviation = MathUtil.getStandardDeviation(this.samples); + final double difference = Math.abs(deviation - this.lastDeviation); + if (difference < 7.52) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("difference=" + difference); + } + } + else { + this.decayBuffer(); + } + this.lastDeviation = deviation; + this.samples.clear(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerI.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerI.java new file mode 100644 index 0000000..c9123e0 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerI.java @@ -0,0 +1,47 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoclicker; + +import java.util.Collection; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import com.google.common.collect.Lists; +import me.frep.vulcan.spigot.data.PlayerData; +import java.util.Deque; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Clicker", type = 'I', complexType = "Kurtosis", description = "Too low kurtosis.") +public class AutoClickerI extends AbstractCheck +{ + private final Deque samples; + + public AutoClickerI(final PlayerData data) { + super(data); + this.samples = Lists.newLinkedList(); + } + + @Override + public void handle(final Packet packet) { + if (packet.isArmAnimation() && !this.isExempt(ExemptType.AUTOCLICKER)) { + final long delay = this.data.getClickProcessor().getDelay(); + if (delay > 5000L) { + this.samples.clear(); + return; + } + this.samples.add(delay); + if (this.samples.size() == 50) { + final double kurtosis = MathUtil.getKurtosis(this.samples); + final double scaled = kurtosis / 1000.0; + if (scaled < 41.78) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("kurtosis=" + scaled); + } + } + else { + this.decayBuffer(); + } + this.samples.clear(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerJ.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerJ.java new file mode 100644 index 0000000..7c7bb48 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerJ.java @@ -0,0 +1,46 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoclicker; + +import java.util.Collections; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import com.google.common.collect.Lists; +import me.frep.vulcan.spigot.data.PlayerData; +import java.util.List; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Clicker", type = 'J', complexType = "Range", description = "Impossible consistency.") +public class AutoClickerJ extends AbstractCheck +{ + private final List samples; + + public AutoClickerJ(final PlayerData data) { + super(data); + this.samples = Lists.newArrayList(); + } + + @Override + public void handle(final Packet packet) { + if (packet.isArmAnimation() && !this.isExempt(ExemptType.AUTOCLICKER)) { + final long delay = this.data.getClickProcessor().getDelay(); + if (delay > 5000L) { + this.samples.clear(); + return; + } + this.samples.add(delay); + if (this.samples.size() == 10) { + Collections.sort(this.samples); + final long range = this.samples.get(this.samples.size() - 1) - this.samples.get(0); + if (range < 50L) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("range=" + range); + } + } + else { + this.decayBuffer(); + } + this.samples.clear(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerK.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerK.java new file mode 100644 index 0000000..4a3b8bc --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerK.java @@ -0,0 +1,49 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoclicker; + +import java.util.Collection; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import com.google.common.collect.Lists; +import me.frep.vulcan.spigot.data.PlayerData; +import java.util.Deque; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Clicker", type = 'K', complexType = "Average Difference", description = "Similar average values.") +public class AutoClickerK extends AbstractCheck +{ + private final Deque samples; + private double lastAverage; + + public AutoClickerK(final PlayerData data) { + super(data); + this.samples = Lists.newLinkedList(); + } + + @Override + public void handle(final Packet packet) { + if (packet.isArmAnimation() && !this.isExempt(ExemptType.AUTOCLICKER)) { + final long delay = this.data.getClickProcessor().getDelay(); + if (delay > 5000L) { + this.samples.clear(); + return; + } + this.samples.add(delay); + if (this.samples.size() == 50) { + final double average = MathUtil.getAverage(this.samples); + final double difference = Math.abs(average - this.lastAverage); + if (difference < 2.56) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("difference=" + difference); + } + } + else { + this.decayBuffer(); + } + this.lastAverage = average; + this.samples.clear(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerL.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerL.java new file mode 100644 index 0000000..6695d00 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerL.java @@ -0,0 +1,49 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoclicker; + +import java.util.Collection; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import com.google.common.collect.Lists; +import me.frep.vulcan.spigot.data.PlayerData; +import java.util.Deque; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Clicker", type = 'L', complexType = "Kurtosis Difference", description = "Similar kurtosis values.") +public class AutoClickerL extends AbstractCheck +{ + private final Deque samples; + private double lastKurtosis; + + public AutoClickerL(final PlayerData data) { + super(data); + this.samples = Lists.newLinkedList(); + } + + @Override + public void handle(final Packet packet) { + if (packet.isArmAnimation() && !this.isExempt(ExemptType.AUTOCLICKER)) { + final long delay = this.data.getClickProcessor().getDelay(); + if (delay > 5000L) { + this.samples.clear(); + return; + } + this.samples.add(delay); + if (this.samples.size() == 50) { + final double kurtosis = MathUtil.getKurtosis(this.samples) / 1000.0; + final double difference = Math.abs(kurtosis - this.lastKurtosis); + if (difference < 8.35) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("difference=" + difference); + } + } + else { + this.decayBuffer(); + } + this.lastKurtosis = kurtosis; + this.samples.clear(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerM.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerM.java new file mode 100644 index 0000000..2105e9d --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerM.java @@ -0,0 +1,49 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoclicker; + +import java.util.Collection; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import com.google.common.collect.Lists; +import me.frep.vulcan.spigot.data.PlayerData; +import java.util.Deque; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Clicker", type = 'M', complexType = "Variance Difference", description = "Similar variance values.") +public class AutoClickerM extends AbstractCheck +{ + private final Deque samples; + private double lastVariance; + + public AutoClickerM(final PlayerData data) { + super(data); + this.samples = Lists.newLinkedList(); + } + + @Override + public void handle(final Packet packet) { + if (packet.isArmAnimation() && !this.isExempt(ExemptType.AUTOCLICKER)) { + final long delay = this.data.getClickProcessor().getDelay(); + if (delay > 5000L) { + this.samples.clear(); + return; + } + this.samples.add(delay); + if (this.samples.size() == 50) { + final double variance = MathUtil.getVariance(this.samples) / 1000.0; + final double difference = Math.abs(variance - this.lastVariance); + if (difference < 5.28) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("difference=" + difference); + } + } + else { + this.decayBuffer(); + } + this.lastVariance = variance; + this.samples.clear(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerN.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerN.java new file mode 100644 index 0000000..1e43121 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerN.java @@ -0,0 +1,48 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoclicker; + +import java.util.Collection; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.util.type.EvictingList; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Clicker", type = 'N', complexType = "Deviation Difference", description = "Low deviation difference.") +public class AutoClickerN extends AbstractCheck +{ + private final EvictingList samples; + private double lastDeviation; + + public AutoClickerN(final PlayerData data) { + super(data); + this.samples = new EvictingList(25); + } + + @Override + public void handle(final Packet packet) { + if (packet.isArmAnimation() && !this.isExempt(ExemptType.AUTOCLICKER)) { + final long delay = this.data.getClickProcessor().getDelay(); + if (delay > 5000L) { + this.samples.clear(); + return; + } + this.samples.add(delay); + if (this.samples.isFull()) { + final double deviation = MathUtil.getStandardDeviation(this.samples); + final double difference = Math.abs(deviation - this.lastDeviation); + final double average = Math.abs(deviation + this.lastDeviation) / 2.0; + if (difference < 0.25 && average < 150.0) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("difference=" + difference + " average=" + average); + } + } + else { + this.decayBuffer(); + } + this.lastDeviation = deviation; + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerO.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerO.java new file mode 100644 index 0000000..4d71595 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerO.java @@ -0,0 +1,54 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoclicker; + +import java.util.Collection; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import com.google.common.collect.Lists; +import me.frep.vulcan.spigot.data.PlayerData; +import java.util.Deque; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Clicker", type = 'O', complexType = "Spikes", description = "Impossible spike in CPS.") +public class AutoClickerO extends AbstractCheck +{ + private final Deque samples; + private double lastCps; + + public AutoClickerO(final PlayerData data) { + super(data); + this.samples = Lists.newLinkedList(); + this.lastCps = -1.0; + } + + @Override + public void handle(final Packet packet) { + if (packet.isArmAnimation() && !this.isExempt(ExemptType.AUTOCLICKER)) { + final long delay = this.data.getClickProcessor().getDelay(); + if (delay > 5000L) { + this.samples.clear(); + return; + } + this.samples.add(delay); + if (this.samples.size() == 10) { + final double cps = MathUtil.getCps(this.samples); + if (this.lastCps > 0.0) { + final double difference = Math.abs(cps - this.lastCps); + final double average = (this.lastCps + cps) / 2.0; + final boolean invalid = average > 9.25 && difference > 2.8; + if (invalid) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("average=" + average + " difference=" + difference); + } + } + else { + this.decayBuffer(); + } + } + this.lastCps = cps; + this.samples.clear(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerP.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerP.java new file mode 100644 index 0000000..654d152 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerP.java @@ -0,0 +1,54 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoclicker; + +import java.util.Collection; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import com.google.common.collect.Lists; +import me.frep.vulcan.spigot.data.PlayerData; +import java.util.Deque; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Clicker", type = 'P', complexType = "Identical", description = "Identical statistical values.") +public class AutoClickerP extends AbstractCheck +{ + private final Deque samples; + private double lastDeviation; + private double lastSkewness; + private double lastKurtosis; + + public AutoClickerP(final PlayerData data) { + super(data); + this.samples = Lists.newLinkedList(); + } + + @Override + public void handle(final Packet packet) { + if (packet.isArmAnimation() && !this.isExempt(ExemptType.AUTOCLICKER)) { + final long delay = this.data.getClickProcessor().getDelay(); + if (delay > 5000L) { + this.samples.clear(); + return; + } + this.samples.add(delay); + if (this.samples.size() == 15) { + final double deviation = MathUtil.getStandardDeviation(this.samples); + final double skewness = MathUtil.getSkewness(this.samples); + final double kurtosis = MathUtil.getKurtosis(this.samples); + if (deviation == this.lastDeviation && skewness == this.lastSkewness && kurtosis == this.lastKurtosis) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail(); + } + } + else { + this.resetBuffer(); + } + this.lastDeviation = deviation; + this.lastSkewness = skewness; + this.lastKurtosis = kurtosis; + this.samples.clear(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerQ.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerQ.java new file mode 100644 index 0000000..df1afaa --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerQ.java @@ -0,0 +1,48 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoclicker; + +import java.util.Collection; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.util.type.EvictingList; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Clicker", type = 'Q', complexType = "Average Deviation", description = "Too low average deviation.") +public class AutoClickerQ extends AbstractCheck +{ + private final EvictingList samples; + private double lastDeviation; + + public AutoClickerQ(final PlayerData data) { + super(data); + this.samples = new EvictingList(40); + } + + @Override + public void handle(final Packet packet) { + if (packet.isArmAnimation() && !this.isExempt(ExemptType.AUTOCLICKER)) { + final long delay = this.data.getClickProcessor().getDelay(); + if (delay > 5000L) { + this.samples.clear(); + return; + } + this.samples.add(delay); + if (this.samples.isFull()) { + final double deviation = MathUtil.getStandardDeviation(this.samples); + final double difference = Math.abs(deviation - this.lastDeviation); + final double average = Math.abs(deviation + this.lastDeviation) / 2.0; + if (difference < 3.0 && average < 150.0) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("difference=" + difference + " average=" + average); + } + } + else { + this.decayBuffer(); + } + this.lastDeviation = deviation; + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerR.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerR.java new file mode 100644 index 0000000..79907fa --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerR.java @@ -0,0 +1,45 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoclicker; + +import java.util.Collection; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.util.type.EvictingList; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Clicker", type = 'R', complexType = "Consistency", description = "Impossible consistency.") +public class AutoClickerR extends AbstractCheck +{ + private final EvictingList samples; + + public AutoClickerR(final PlayerData data) { + super(data); + this.samples = new EvictingList(30); + } + + @Override + public void handle(final Packet packet) { + if (packet.isArmAnimation() && !this.isExempt(ExemptType.AUTOCLICKER)) { + final long delay = this.data.getClickProcessor().getDelay(); + if (delay > 5000L) { + this.samples.clear(); + return; + } + this.samples.add(delay); + if (this.samples.isFull()) { + final int outliers = (int)this.samples.stream().filter(l -> l > 150L).count(); + final double average = MathUtil.getAverage(this.samples); + if (outliers == 0) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("outliers=" + outliers + " average=" + average); + } + } + else { + this.decayBuffer(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerS.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerS.java new file mode 100644 index 0000000..5ca9e17 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerS.java @@ -0,0 +1,44 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoclicker; + +import java.util.Collection; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.util.type.EvictingList; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Clicker", type = 'S', complexType = "Distinct", description = "Checks for amount of distinct delays.") +public class AutoClickerS extends AbstractCheck +{ + private final EvictingList samples; + + public AutoClickerS(final PlayerData data) { + super(data); + this.samples = new EvictingList(25); + } + + @Override + public void handle(final Packet packet) { + if (packet.isArmAnimation() && !this.isExempt(ExemptType.AUTOCLICKER)) { + final long delay = this.data.getClickProcessor().getDelay(); + if (delay > 5000L) { + this.samples.clear(); + return; + } + this.samples.add(delay); + if (this.samples.isFull()) { + final int distinct = MathUtil.getDistinct(this.samples); + if (distinct < 6) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("distinct=" + distinct); + } + } + else { + this.decayBuffer(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerT.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerT.java new file mode 100644 index 0000000..5e4d72b --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/autoclicker/AutoClickerT.java @@ -0,0 +1,46 @@ +package me.frep.vulcan.spigot.check.impl.combat.autoclicker; + +import me.frep.vulcan.spigot.config.Config; +import java.util.Collection; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.util.type.EvictingList; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Auto Clicker", type = 'T', complexType = "Kurtosis", description = "Too low kurtosis") +public class AutoClickerT extends AbstractCheck +{ + private final EvictingList samples; + + public AutoClickerT(final PlayerData data) { + super(data); + this.samples = new EvictingList(25); + } + + @Override + public void handle(final Packet packet) { + if (packet.isArmAnimation() && !this.isExempt(ExemptType.AUTOCLICKER)) { + final long delay = this.data.getClickProcessor().getDelay(); + if (delay > 5000L) { + this.samples.clear(); + return; + } + this.samples.add(delay); + if (this.samples.isFull()) { + final double kurtosis = MathUtil.getKurtosis(this.samples) / 1000.0; + this.data.getClickProcessor().setKurtosis(kurtosis); + if (kurtosis < Config.AUTOCLICKER_T_MIN_KURTOSIS) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("kurtosis=" + kurtosis); + } + } + else { + this.decayBuffer(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/criticals/CriticalsA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/criticals/CriticalsA.java new file mode 100644 index 0000000..a135deb --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/criticals/CriticalsA.java @@ -0,0 +1,36 @@ +package me.frep.vulcan.spigot.check.impl.combat.criticals; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Criticals", type = 'A', complexType = "Ground", description = "Tried to hit Critical hit on ground.") +public class CriticalsA extends AbstractCheck +{ + public CriticalsA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isUseEntity() && this.hitTicks() < 2) { + final double deltaY = Math.abs(this.data.getPositionProcessor().getDeltaY()); + final double modulo = this.data.getPositionProcessor().getY() % 0.015625; + final boolean exempt = this.isExempt(ExemptType.LIQUID, ExemptType.TRAPDOOR, ExemptType.COLLIDING_VERTICALLY, ExemptType.TELEPORT, ExemptType.BOAT, ExemptType.TELEPORT, ExemptType.WEB, ExemptType.ENDER_PEARL, ExemptType.CHORUS_FRUIT, ExemptType.ELYTRA, ExemptType.SERVER_POSITION, ExemptType.CARPET, ExemptType.VEHICLE, ExemptType.FARMLAND, ExemptType.GLIDING, ExemptType.SLAB) || this.data.getPositionProcessor().isNearPath(); + if (Math.abs(deltaY - 7.504558659832128E-4) < 0.001) { + return; + } + final boolean invalid = (deltaY < 0.001 && deltaY > 0.0 && modulo < 1.0E-5) || deltaY == 0.0625; + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaY=" + deltaY + " modulo=" + modulo); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/criticals/CriticalsB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/criticals/CriticalsB.java new file mode 100644 index 0000000..402867b --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/criticals/CriticalsB.java @@ -0,0 +1,32 @@ +package me.frep.vulcan.spigot.check.impl.combat.criticals; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Criticals", type = 'B', complexType = "Modulo", description = "Tried to hit Critical hit on ground.") +public class CriticalsB extends AbstractCheck +{ + public CriticalsB(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isUseEntity() && this.hitTicks() < 2) { + final double modulo = this.data.getPositionProcessor().getY() % 0.015625; + final boolean invalid = modulo < 1.0E-5 && modulo > 0.0; + final boolean exempt = this.isExempt(ExemptType.LIQUID, ExemptType.TRAPDOOR, ExemptType.COLLIDING_VERTICALLY, ExemptType.BOAT, ExemptType.TELEPORT, ExemptType.WEB, ExemptType.ENDER_PEARL, ExemptType.CHORUS_FRUIT, ExemptType.SERVER_POSITION, ExemptType.VEHICLE, ExemptType.FLIGHT, ExemptType.SLAB); + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("modulo=" + modulo); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/fastbow/FastBowA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/fastbow/FastBowA.java new file mode 100644 index 0000000..1af8852 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/fastbow/FastBowA.java @@ -0,0 +1,45 @@ +package me.frep.vulcan.spigot.check.impl.combat.fastbow; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.ServerUtil; +import org.bukkit.entity.Arrow; +import org.bukkit.event.entity.ProjectileLaunchEvent; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Fast Bow", type = 'A', complexType = "Limit", description = "Shooting a bow too quickly") +public class FastBowA extends AbstractCheck +{ + private long lastShot; + + public FastBowA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isProjectileLaunchEvent()) { + final ProjectileLaunchEvent event = (ProjectileLaunchEvent)packet.getRawPacket().getRawNMSPacket(); + if (event.getEntity() instanceof Arrow) { + final Arrow arrow = (Arrow)event.getEntity(); + final boolean crossbow = this.data.getPlayer().getItemInHand().getType().toString().contains("CROSS") || (ServerUtil.isHigherThan1_9() && this.data.getPlayer().getInventory().getItemInOffHand().getType().toString().contains("CROSS")); + final boolean holdingBow = this.data.getPlayer().getItemInHand().getType().toString().contains("BOW") || (ServerUtil.isHigherThan1_9() && this.data.getPlayer().getInventory().getItemInOffHand().getType().toString().contains("BOW")); + if (arrow.getVelocity().length() > 2.0 && !crossbow && holdingBow) { + final long delay = System.currentTimeMillis() - this.lastShot; + final boolean exempt = this.isExempt(ExemptType.FAST); + if (delay < 750L && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("length=" + arrow.getVelocity().length() + " delay=" + delay); + } + } + else { + this.decayBuffer(); + } + this.lastShot = System.currentTimeMillis(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/hitbox/HitboxA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/hitbox/HitboxA.java new file mode 100644 index 0000000..babdd55 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/hitbox/HitboxA.java @@ -0,0 +1,88 @@ +package me.frep.vulcan.spigot.check.impl.combat.hitbox; + +import me.frep.vulcan.spigot.util.type.Pair; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import org.bukkit.Location; +import org.bukkit.util.Vector; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.entity.Player; +import io.github.retrooper.packetevents.packetwrappers.play.in.useentity.WrappedPacketInUseEntity; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Hitbox", type = 'A', complexType = "History", description = "Attacked while not looking at target.") +public class HitboxA extends AbstractCheck +{ + private boolean attacking; + + public HitboxA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isUseEntity()) { + final WrappedPacketInUseEntity wrapper = this.data.getUseEntityWrapper(); + if (wrapper.getAction() != WrappedPacketInUseEntity.EntityUseAction.ATTACK || !(wrapper.getEntity() instanceof Player)) { + return; + } + this.attacking = true; + } + else if (packet.isFlying()) { + if (this.attacking) { + final int ticks = Vulcan.INSTANCE.getTickManager().getTicks(); + final int pingTicks = MathUtil.getPingInTicks(this.data); + final double x = this.data.getPositionProcessor().getX(); + final double z = this.data.getPositionProcessor().getZ(); + final Vector origin = new Vector(x, 0.0, z); + final double angle = this.data.getCombatProcessor().getTargetLocations().stream().filter(pair -> Math.abs(ticks - pair.getY() - pingTicks) < 3).mapToDouble(pair -> { + final Vector targetLocation = pair.getX().toVector().setY(0.0); + final Vector direction = targetLocation.clone().subtract(origin); + final Vector target = this.getDirection(this.data.getRotationProcessor().getYaw(), this.data.getRotationProcessor().getPitch()).setY(0.0); + return (double)direction.angle(target); + }).min().orElse(-1.0); + final double distance = this.data.getCombatProcessor().getDistance(); + if (angle == -1.0) { + this.decreaseBufferBy(0.025); + } + else { + final PlayerData targetData = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(this.data.getCombatProcessor().getTrackedPlayer()); + if (targetData == null) { + return; + } + final boolean targetExempt = targetData.getExemptProcessor().isExempt(ExemptType.VEHICLE, ExemptType.BOAT); + double maxAngle = Config.HITBOX_A_MAX_ANGLE; + if (System.currentTimeMillis() - this.data.getConnectionProcessor().getLastFast() < 1500L) { + maxAngle += 0.125; + } + final boolean exempt = this.isExempt(ExemptType.CREATIVE, ExemptType.GLIDING, ExemptType.VEHICLE); + final float deltaYaw = this.data.getRotationProcessor().getDeltaYaw(); + if (angle > maxAngle && distance > 1.5 && distance < 10.0 && !exempt && !targetExempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("angle=" + angle + " distance=" + distance + " dYaw=" + deltaYaw); + } + } + else { + this.decayBuffer(); + } + } + } + this.attacking = false; + } + } + + private Vector getDirection(final float yaw, final float pitch) { + final Vector vector = new Vector(); + final double rotX = yaw; + final double rotY = pitch; + vector.setY(-Math.sin(Math.toRadians(rotY))); + final double xz = Math.cos(Math.toRadians(rotY)); + vector.setX(-xz * Math.sin(Math.toRadians(rotX))); + vector.setZ(xz * Math.cos(Math.toRadians(rotX))); + return vector; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/hitbox/HitboxB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/hitbox/HitboxB.java new file mode 100644 index 0000000..7215efc --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/hitbox/HitboxB.java @@ -0,0 +1,69 @@ +package me.frep.vulcan.spigot.check.impl.combat.hitbox; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.config.Config; +import org.bukkit.util.Vector; +import me.frep.vulcan.spigot.Vulcan; +import io.github.retrooper.packetevents.packetwrappers.play.in.useentity.WrappedPacketInUseEntity; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import org.bukkit.entity.Player; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Hitbox", type = 'B', complexType = "Simple", description = "Attacked while not looking at target.") +public class HitboxB extends AbstractCheck +{ + private boolean attacking; + private Player target; + + public HitboxB(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isUseEntity()) { + final WrappedPacketInUseEntity wrapper = this.data.getUseEntityWrapper(); + if (wrapper.getAction() != WrappedPacketInUseEntity.EntityUseAction.ATTACK || !(wrapper.getEntity() instanceof Player)) { + return; + } + this.target = (Player)wrapper.getEntity(); + this.attacking = true; + } + else if (packet.isFlying()) { + if (this.attacking && this.target != null) { + final PlayerData targetData = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(this.target); + if (targetData == null) { + return; + } + final double deltaX = targetData.getPositionProcessor().getX() - this.data.getPositionProcessor().getX(); + final double deltaZ = targetData.getPositionProcessor().getZ() - this.data.getPositionProcessor().getZ(); + final float yaw = this.data.getRotationProcessor().getYaw(); + final double directionX = -Math.sin(yaw * 3.1415927f / 180.0f) * 1.0 * 0.5; + final double directionZ = Math.cos(yaw * 3.1415927f / 180.0f) * 1.0 * 0.5; + final Vector direction = new Vector(directionX, 0.0, directionZ); + final Vector positionDifference = new Vector(deltaX, 0.0, deltaZ); + final double distance = this.data.getCombatProcessor().getDistance(); + final double angle = Math.toDegrees(positionDifference.angle(direction)); + double maxAngle = Config.HITBOX_B_MAX_ANGLE; + double maxDistance = 1.25; + if (System.currentTimeMillis() - this.data.getConnectionProcessor().getLastFast() < 1500L) { + maxAngle += 0.125; + maxDistance += 0.1; + } + final boolean targetExempt = targetData.getExemptProcessor().isExempt(ExemptType.VEHICLE, ExemptType.BOAT); + final boolean exempt = this.isExempt(ExemptType.CREATIVE, ExemptType.CREATIVE, ExemptType.VEHICLE); + if (angle > maxAngle && distance > 1.3 && distance < 10.0 && !exempt && !targetExempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("angle=" + angle + " distance=" + distance); + } + } + else { + this.decayBuffer(); + } + } + this.attacking = false; + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraA.java new file mode 100644 index 0000000..5affaaa --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraA.java @@ -0,0 +1,51 @@ +package me.frep.vulcan.spigot.check.impl.combat.killaura; + +import io.github.retrooper.packetevents.packetwrappers.play.in.useentity.WrappedPacketInUseEntity; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Kill Aura", type = 'A', complexType = "Post", description = "Post UseEntity packets.") +public class KillAuraA extends AbstractCheck +{ + private long lastFlying; + private boolean sent; + + public KillAuraA(final PlayerData data) { + super(data); + this.lastFlying = 0L; + this.sent = false; + } + + @Override + public void handle(final Packet packet) { + if (packet.isFlying()) { + final long delay = System.currentTimeMillis() - this.lastFlying; + if (this.sent) { + final boolean exempt = this.isExempt(ExemptType.SPECTATOR); + if (delay > 40L && delay < 100L && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("delay=" + delay); + } + } + else { + this.decayBuffer(); + } + this.sent = false; + } + this.lastFlying = System.currentTimeMillis(); + } + else if (packet.isUseEntity()) { + final WrappedPacketInUseEntity wrapper = this.data.getUseEntityWrapper(); + if (wrapper.getAction() != WrappedPacketInUseEntity.EntityUseAction.ATTACK) { + return; + } + final long delay2 = System.currentTimeMillis() - this.lastFlying; + if (delay2 < 10L) { + this.sent = true; + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraB.java new file mode 100644 index 0000000..bebe904 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraB.java @@ -0,0 +1,41 @@ +package me.frep.vulcan.spigot.check.impl.combat.killaura; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import io.github.retrooper.packetevents.utils.player.ClientVersion; +import org.bukkit.entity.Player; +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Kill Aura", type = 'B', complexType = "Acceleration", experimental = false, description = "Invalid acceleration.") +public class KillAuraB extends AbstractCheck +{ + public KillAuraB(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && this.hitTicks() < 3) { + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double acceleration = this.data.getPositionProcessor().getAcceleration(); + final float baseSpeed = PlayerUtil.getBaseSpeed(this.data, 0.21f); + final long swingDelay = this.data.getClickProcessor().getDelay(); + final boolean sprinting = this.data.getActionProcessor().isSprinting(); + final boolean validTarget = this.data.getCombatProcessor().getTarget() != null && this.data.getCombatProcessor().getTarget() instanceof Player; + final boolean validVersion = PlayerUtil.getClientVersion(this.data.getPlayer()).isLowerThan(ClientVersion.v_1_9); + final boolean exempt = this.isExempt(ExemptType.SOUL_SAND); + final boolean invalid = acceleration < 0.0025 && sprinting && deltaXZ > baseSpeed && swingDelay < 500L && validTarget && validVersion; + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("a=" + acceleration); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraC.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraC.java new file mode 100644 index 0000000..b9c3ceb --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraC.java @@ -0,0 +1,35 @@ +package me.frep.vulcan.spigot.check.impl.combat.killaura; + +import org.bukkit.entity.Player; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Kill Aura", type = 'C', complexType = "Head Snap", experimental = false, description = "Invalid acceleration.") +public class KillAuraC extends AbstractCheck +{ + public KillAuraC(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && this.hitTicks() < 3) { + final double acceleration = this.data.getPositionProcessor().getAcceleration(); + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final float deltaYaw = this.data.getRotationProcessor().getDeltaYaw(); + final float deltaPitch = this.data.getRotationProcessor().getDeltaPitch(); + final boolean validTarget = this.data.getCombatProcessor().getTarget() instanceof Player; + final boolean invalid = acceleration < 0.001 && deltaYaw > 10.0f && deltaPitch > 26.5 && validTarget && deltaXZ > 0.0; + if (invalid) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("accel=" + acceleration + " deltaYaw=" + deltaYaw); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraD.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraD.java new file mode 100644 index 0000000..5f917f5 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraD.java @@ -0,0 +1,38 @@ +package me.frep.vulcan.spigot.check.impl.combat.killaura; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import io.github.retrooper.packetevents.packetwrappers.play.in.useentity.WrappedPacketInUseEntity; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Kill Aura", type = 'D', complexType = "Multi Aura", experimental = false, description = "Attacked two entities at once.") +public class KillAuraD extends AbstractCheck +{ + private int lastEntityId; + private int ticks; + + public KillAuraD(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isUseEntity()) { + final WrappedPacketInUseEntity wrapper = this.data.getUseEntityWrapper(); + if (wrapper.getAction() != WrappedPacketInUseEntity.EntityUseAction.ATTACK) { + return; + } + final boolean exempt = this.isExempt(ExemptType.CLIENT_VERSION, ExemptType.SERVER_VERSION); + final int id = wrapper.getEntityId(); + if (id != this.lastEntityId && !exempt && ++this.ticks > 1) { + this.fail("id=" + id + " lastId=" + this.lastEntityId); + } + this.lastEntityId = id; + } + else if (packet.isFlying()) { + this.ticks = 0; + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraF.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraF.java new file mode 100644 index 0000000..1bb35e9 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraF.java @@ -0,0 +1,57 @@ +package me.frep.vulcan.spigot.check.impl.combat.killaura; + +import io.github.retrooper.packetevents.packetwrappers.play.in.useentity.WrappedPacketInUseEntity; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Kill Aura", type = 'F', complexType = "Switch", experimental = false, description = "Switching targets too quickly.") +public class KillAuraF extends AbstractCheck +{ + private int lastEntityId; + private int hits; + private int swings; + private long lastSwitch; + + public KillAuraF(final PlayerData data) { + super(data); + this.lastSwitch = -1L; + } + + @Override + public void handle(final Packet packet) { + if (packet.isUseEntity()) { + final WrappedPacketInUseEntity wrapper = this.data.getUseEntityWrapper(); + if (wrapper.getAction() != WrappedPacketInUseEntity.EntityUseAction.ATTACK) { + return; + } + if (wrapper.getEntityId() != this.lastEntityId) { + this.lastSwitch = System.currentTimeMillis(); + } + ++this.hits; + this.lastEntityId = wrapper.getEntityId(); + } + else if (packet.isArmAnimation()) { + ++this.swings; + } + else if (packet.isFlying() && this.hitTicks() < 2 && this.swings > 0) { + final double ratio = this.hits / (double)this.swings * 100.0; + final double deltaYaw = this.data.getRotationProcessor().getDeltaYaw(); + final long delay = System.currentTimeMillis() - this.lastSwitch; + if (this.hits > 20 && ratio > 85.0 && delay < 5L && deltaYaw > 15.0) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ratio=" + ratio + " delay=" + delay); + } + } + else { + this.decayBuffer(); + } + if (this.hits > 40 || this.swings > 40) { + final int n = 0; + this.swings = n; + this.hits = n; + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraH.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraH.java new file mode 100644 index 0000000..16c5ce0 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraH.java @@ -0,0 +1,40 @@ +package me.frep.vulcan.spigot.check.impl.combat.killaura; + +import me.frep.vulcan.spigot.util.PlayerUtil; +import io.github.retrooper.packetevents.packetwrappers.play.in.clientcommand.WrappedPacketInClientCommand; +import io.github.retrooper.packetevents.packetwrappers.play.in.useentity.WrappedPacketInUseEntity; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Kill Aura", type = 'H', complexType = "Inventory", experimental = false, description = "Attacked while opening inventory.") +public class KillAuraH extends AbstractCheck +{ + private boolean attacked; + + public KillAuraH(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isFlying()) { + this.attacked = false; + } + else if (packet.isUseEntity()) { + final WrappedPacketInUseEntity wrapper = this.data.getUseEntityWrapper(); + if (wrapper.getAction() == WrappedPacketInUseEntity.EntityUseAction.ATTACK) { + this.attacked = true; + } + } + else if (packet.isClientCommand()) { + final WrappedPacketInClientCommand wrapper2 = new WrappedPacketInClientCommand(packet.getRawPacket()); + if (wrapper2.getClientCommand() == WrappedPacketInClientCommand.ClientCommand.OPEN_INVENTORY_ACHIEVEMENT && this.attacked) { + if (!PlayerUtil.isHigherThan1_9(this.data.getPlayer())) { + this.fail(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraJ.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraJ.java new file mode 100644 index 0000000..12bb955 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraJ.java @@ -0,0 +1,53 @@ +package me.frep.vulcan.spigot.check.impl.combat.killaura; + +import io.github.retrooper.packetevents.packetwrappers.play.in.useentity.WrappedPacketInUseEntity; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Kill Aura", type = 'J', complexType = "Frequency", experimental = false, description = "Attack frequency.") +public class KillAuraJ extends AbstractCheck +{ + private int movements; + private int lastMovements; + private int total; + private int invalid; + + public KillAuraJ(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isUseEntity()) { + final WrappedPacketInUseEntity wrapper = this.data.getUseEntityWrapper(); + if (wrapper.getAction() == WrappedPacketInUseEntity.EntityUseAction.ATTACK) { + final boolean proper = this.data.getClickProcessor().getCps() > 7.2 && this.movements < 4 && this.lastMovements < 4; + if (proper) { + final boolean flag = this.movements == this.lastMovements; + if (flag) { + ++this.invalid; + } + if (++this.total == 30) { + if (this.invalid > 28) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("invalid=" + this.invalid); + } + } + else { + this.decayBuffer(); + } + this.invalid = 0; + this.total = 0; + } + } + this.lastMovements = this.movements; + this.movements = 0; + } + } + else if (packet.isFlying()) { + ++this.movements; + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraK.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraK.java new file mode 100644 index 0000000..154a204 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraK.java @@ -0,0 +1,49 @@ +package me.frep.vulcan.spigot.check.impl.combat.killaura; + +import java.util.Collections; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import io.github.retrooper.packetevents.packetwrappers.play.in.useentity.WrappedPacketInUseEntity; +import me.frep.vulcan.spigot.packet.Packet; +import com.google.common.collect.Lists; +import me.frep.vulcan.spigot.data.PlayerData; +import java.util.List; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Kill Aura", type = 'K', complexType = "Pattern", description = "Attack pattern.") +public class KillAuraK extends AbstractCheck +{ + private final List samples; + private long lastAttack; + + public KillAuraK(final PlayerData data) { + super(data); + this.samples = Lists.newArrayList(); + } + + @Override + public void handle(final Packet packet) { + if (packet.isUseEntity()) { + final WrappedPacketInUseEntity wrapper = this.data.getUseEntityWrapper(); + if (wrapper.getAction() != WrappedPacketInUseEntity.EntityUseAction.ATTACK || this.isExempt(ExemptType.FAST)) { + return; + } + final long delay = System.currentTimeMillis() - this.lastAttack; + this.samples.add(delay); + if (this.samples.size() == 10) { + Collections.sort(this.samples); + final long range = this.samples.get(this.samples.size() - 1) - this.samples.get(0); + if (range < 50L) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("range=" + range); + } + } + else { + this.decayBuffer(); + } + this.samples.clear(); + } + this.lastAttack = System.currentTimeMillis(); + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraL.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraL.java new file mode 100644 index 0000000..ef2246a --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/killaura/KillAuraL.java @@ -0,0 +1,42 @@ +package me.frep.vulcan.spigot.check.impl.combat.killaura; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import io.github.retrooper.packetevents.utils.player.ClientVersion; +import org.bukkit.entity.Player; +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Kill Aura", type = 'L', complexType = "Strafe", experimental = true, description = "Impossible strafe.") +public class KillAuraL extends AbstractCheck +{ + public KillAuraL(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && this.hitTicks() < 3) { + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double acceleration = this.data.getPositionProcessor().getAcceleration(); + final float baseSpeed = PlayerUtil.getBaseSpeed(this.data, 0.275f); + final long swingDelay = this.data.getClickProcessor().getDelay(); + final boolean sprinting = this.data.getActionProcessor().isSprinting(); + final boolean validTarget = this.data.getCombatProcessor().getTarget() != null && this.data.getCombatProcessor().getTarget() instanceof Player; + final boolean validVersion = PlayerUtil.getClientVersion(this.data.getPlayer()) != null && PlayerUtil.getClientVersion(this.data.getPlayer()).isLowerThan(ClientVersion.v_1_9); + final boolean combo = this.data.getPlayer().getMaximumNoDamageTicks() < 18 || (validTarget && ((Player)this.data.getCombatProcessor().getTarget()).getMaximumNoDamageTicks() < 18); + final boolean exempt = this.isExempt(ExemptType.SOUL_SAND); + final boolean invalid = acceleration < 0.0025 && !sprinting && deltaXZ > baseSpeed && swingDelay < 500L && validTarget && validVersion; + if (invalid && !exempt && !combo) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("d=" + deltaXZ + " a=" + acceleration + " s=" + swingDelay); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/reach/ReachA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/reach/ReachA.java new file mode 100644 index 0000000..6c2d080 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/reach/ReachA.java @@ -0,0 +1,74 @@ +package me.frep.vulcan.spigot.check.impl.combat.reach; + +import me.frep.vulcan.spigot.util.type.Pair; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.Location; +import org.bukkit.util.Vector; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.entity.Player; +import io.github.retrooper.packetevents.packetwrappers.play.in.useentity.WrappedPacketInUseEntity; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Reach", type = 'A', complexType = "History", description = "Hit from too far away.") +public class ReachA extends AbstractCheck +{ + private boolean attacking; + + public ReachA(final PlayerData data) { + super(data); + this.attacking = true; + } + + @Override + public void handle(final Packet packet) { + if (packet.isUseEntity()) { + final WrappedPacketInUseEntity wrapper = this.data.getUseEntityWrapper(); + if (wrapper.getAction() != WrappedPacketInUseEntity.EntityUseAction.ATTACK || !(wrapper.getEntity() instanceof Player)) { + return; + } + this.attacking = true; + } + else if (packet.isFlying() && this.attacking) { + final int ticks = Vulcan.INSTANCE.getTickManager().getTicks(); + final int pingTicks = MathUtil.getPingInTicks(this.data); + final double x = this.data.getPositionProcessor().getX(); + final double z = this.data.getPositionProcessor().getZ(); + final Vector origin = new Vector(x, 0.0, z); + final double distance = this.data.getCombatProcessor().getTargetLocations().stream().filter(pair -> Math.abs(ticks - pair.getY() - pingTicks) < 3).mapToDouble(pair -> { + final Vector victimVector = pair.getX().toVector().setY(0); + return origin.distance(victimVector) - 0.52; + }).min().orElse(-1.0); + if (distance == -1.0) { + this.decreaseBufferBy(0.025); + } + else { + final PlayerData targetData = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(this.data.getCombatProcessor().getTrackedPlayer()); + if (targetData == null) { + return; + } + final boolean knockback = this.data.getPlayer().getItemInHand().getEnchantmentLevel(Enchantment.KNOCKBACK) > 0; + final boolean exempt = this.isExempt(ExemptType.CREATIVE, ExemptType.VEHICLE, ExemptType.BOAT); + final boolean targetExempt = targetData.getExemptProcessor().isExempt(ExemptType.VEHICLE, ExemptType.BOAT); + double max = Config.REACH_A_MAX_REACH; + if (System.currentTimeMillis() - this.data.getConnectionProcessor().getLastFast() < 1500L) { + max += 1.15; + } + if (distance > max && distance < 8.0 && !knockback && !exempt && !targetExempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("distance=" + distance); + } + } + else { + this.decayBuffer(); + } + } + this.attacking = false; + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/reach/ReachB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/reach/ReachB.java new file mode 100644 index 0000000..c24666b --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/reach/ReachB.java @@ -0,0 +1,87 @@ +package me.frep.vulcan.spigot.check.impl.combat.reach; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.config.Config; +import org.bukkit.util.Vector; +import me.frep.vulcan.spigot.Vulcan; +import io.github.retrooper.packetevents.packetwrappers.play.in.useentity.WrappedPacketInUseEntity; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import org.bukkit.entity.Player; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Reach", type = 'B', complexType = "Simple", description = "Hit from too far away.") +public class ReachB extends AbstractCheck +{ + private boolean attacking; + private Player target; + + public ReachB(final PlayerData data) { + super(data); + this.attacking = false; + } + + @Override + public void handle(final Packet packet) { + if (packet.isUseEntity()) { + final WrappedPacketInUseEntity wrapper = this.data.getUseEntityWrapper(); + if (wrapper.getAction() != WrappedPacketInUseEntity.EntityUseAction.ATTACK || !(wrapper.getEntity() instanceof Player)) { + this.target = null; + this.attacking = false; + return; + } + this.attacking = true; + this.target = (Player)wrapper.getEntity(); + } + else if (packet.isFlying() && this.attacking && this.target != null) { + final PlayerData targetData = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(this.target); + if (targetData == null) { + return; + } + final double x = this.data.getPositionProcessor().getX(); + final double y = this.data.getPositionProcessor().getY(); + final double z = this.data.getPositionProcessor().getZ(); + final Vector origin = new Vector(x, 0.0, z); + final double targetX = targetData.getPositionProcessor().getX(); + final double targetY = targetData.getPositionProcessor().getY(); + final double targetZ = targetData.getPositionProcessor().getZ(); + final Vector targetVector = new Vector(targetX, 0.0, targetZ); + final double yDifference = Math.abs(y - targetY); + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double distance = origin.distance(targetVector) - 0.565; + final int groundTicks = this.data.getPositionProcessor().getClientGroundTicks(); + double maxDistance = Config.REACH_B_MAX_REACH + 0.05; + maxDistance += yDifference * 0.9; + maxDistance += deltaXZ * 0.66; + if (this.data.getActionProcessor().isSprinting()) { + maxDistance += 0.32; + } + if (groundTicks < 3) { + maxDistance += 0.35; + } + if (this.data.getActionProcessor().isHasSpeed()) { + maxDistance += this.data.getActionProcessor().getSpeedAmplifier() * 0.125; + } + final double yawDiff = PlayerUtil.getYawDiff(this.data.getPlayer(), targetData.getPlayer()); + if (yawDiff > 100.0) { + maxDistance += 1.25; + } + final boolean exempt = this.isExempt(ExemptType.TELEPORT, ExemptType.JOINED, ExemptType.PLUGIN_LOAD, ExemptType.WORLD_CHANGE, ExemptType.CREATIVE, ExemptType.VEHICLE); + if (this.isExempt(ExemptType.SERVER_POSITION) || System.currentTimeMillis() - this.data.getConnectionProcessor().getLastFast() < 1500L) { + ++maxDistance; + } + final boolean targetExempt = targetData.getExemptProcessor().isExempt(ExemptType.VEHICLE, ExemptType.BOAT); + if (distance > maxDistance && distance < 6.0 && !exempt && !targetExempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail(distance + " > " + maxDistance); + } + } + else { + this.decayBuffer(); + } + this.attacking = false; + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/velocity/VelocityA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/velocity/VelocityA.java new file mode 100644 index 0000000..5e499f8 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/velocity/VelocityA.java @@ -0,0 +1,53 @@ +package me.frep.vulcan.spigot.check.impl.combat.velocity; + +import me.frep.vulcan.spigot.data.processor.VelocityProcessor; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Velocity", type = 'A', complexType = "Vertical", description = "Vertical velocity modifications.") +public class VelocityA extends AbstractCheck +{ + public VelocityA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isFlying()) { + final boolean push = this.data.getActionProcessor().getSincePushTicks() < 20; + if (push || this.data.getPositionProcessor().isNearBorder()) { + return; + } + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final VelocityProcessor.VelocitySnapshot snapshot = this.data.getVelocityProcessor().getSnapshot(); + if (snapshot == null) { + return; + } + final double velocityY = snapshot.getVelocity().getY(); + if (velocityY < 0.01) { + return; + } + final int ticksSinceVelocity = this.data.getVelocityProcessor().getTransactionFlyingTicks(); + final double ratio = deltaY / velocityY; + final boolean poison = this.data.getActionProcessor().getSincePoisonDamageTicks() < 10; + if (ticksSinceVelocity == 1 && !poison) { + final boolean exempt = this.isExempt(ExemptType.COLLIDING_VERTICALLY, ExemptType.LIQUID, ExemptType.FROZEN, ExemptType.CHUNK, ExemptType.FALL_DAMAGE, ExemptType.ENDER_PEARL, ExemptType.WEB, ExemptType.VOID, ExemptType.SLOW_FALLING, ExemptType.ENDER_PEARL, ExemptType.TRAPDOOR, ExemptType.SOUL_SAND, ExemptType.SLIME, ExemptType.COMBO_MODE, ExemptType.FLIGHT, ExemptType.ATTRIBUTE_MODIFIER, ExemptType.NETHERITE_ARMOR, ExemptType.FULLY_STUCK, ExemptType.PARTIALLY_STUCK, ExemptType.VEHICLE, ExemptType.MYTHIC_MOB, ExemptType.ELYTRA, ExemptType.FIREBALL, ExemptType.SWEET_BERRIES, ExemptType.BUKKIT_VELOCITY, ExemptType.PLACED_WEB); + double minRatio = 0.999; + if (this.isExempt(ExemptType.COLLIDING_HORIZONTALLY)) { + minRatio -= 0.1; + } + if (ratio < minRatio && velocityY > 0.0 && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("tick=1 percent=" + ratio * 100.0 + "% deltaY=" + deltaY + " velocity=" + velocityY); + } + } + else { + this.decayBuffer(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/velocity/VelocityB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/velocity/VelocityB.java new file mode 100644 index 0000000..f487268 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/velocity/VelocityB.java @@ -0,0 +1,55 @@ +package me.frep.vulcan.spigot.check.impl.combat.velocity; + +import me.frep.vulcan.spigot.data.processor.VelocityProcessor; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Velocity", type = 'B', complexType = "Horizontal", description = "Horizontal velocity modifications.") +public class VelocityB extends AbstractCheck +{ + public VelocityB(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isFlying()) { + final boolean push = this.data.getActionProcessor().getSincePushTicks() < 20; + if (push || this.data.getPositionProcessor().isNearBorder()) { + return; + } + final boolean collidingHorizontally = this.data.getPositionProcessor().isCollidingHorizontally(); + final boolean collidingVertically = this.data.getPositionProcessor().isCollidingVertically(); + if (!collidingHorizontally) { + if (!collidingVertically) { + final int velocityTicks = this.data.getVelocityProcessor().getTransactionFlyingTicks(); + if (velocityTicks == 1) { + final VelocityProcessor.VelocitySnapshot snapshot = this.data.getVelocityProcessor().getSnapshot(); + if (snapshot == null) { + return; + } + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double velocityXZ = MathUtil.hypot(snapshot.getVelocity().getX(), snapshot.getVelocity().getZ()); + if (velocityXZ < 0.01) { + return; + } + final double ratio = deltaXZ / velocityXZ; + final boolean exempt = this.isExempt(ExemptType.COLLIDING_VERTICALLY, ExemptType.LIQUID, ExemptType.FROZEN, ExemptType.CHUNK, ExemptType.FALL_DAMAGE, ExemptType.ENDER_PEARL, ExemptType.WEB, ExemptType.VOID, ExemptType.SLOW_FALLING, ExemptType.PLACED_WEB, ExemptType.ENDER_PEARL, ExemptType.TRAPDOOR, ExemptType.SOUL_SAND, ExemptType.SLIME, ExemptType.COMBO_MODE, ExemptType.FLIGHT, ExemptType.ATTRIBUTE_MODIFIER, ExemptType.NETHERITE_ARMOR, ExemptType.FULLY_STUCK, ExemptType.BUKKIT_VELOCITY, ExemptType.PARTIALLY_STUCK, ExemptType.VEHICLE, ExemptType.MYTHIC_MOB, ExemptType.ELYTRA, ExemptType.SWEET_BERRIES); + if (ratio < 0.21 && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("percent=" + ratio * 100.0 + "% deltaXZ=" + deltaXZ + " velocityXZ=" + velocityXZ); + } + } + else { + this.decayBuffer(); + } + } + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/velocity/VelocityC.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/velocity/VelocityC.java new file mode 100644 index 0000000..c46be1c --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/velocity/VelocityC.java @@ -0,0 +1,101 @@ +package me.frep.vulcan.spigot.check.impl.combat.velocity; + +import me.frep.vulcan.spigot.data.processor.VelocityProcessor; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Velocity", type = 'C', complexType = "Ignored Vertical", description = "Vertical velocity modifications.") +public class VelocityC extends AbstractCheck +{ + private boolean lastSprint; + private double firstTickBuffer; + private double secondTickBuffer; + private double thirdTickBuffer; + private double fourthTickBuffer; + + public VelocityC(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isFlying()) { + final boolean push = this.data.getActionProcessor().getSincePushTicks() < 20; + if (push || this.data.getPositionProcessor().isNearBorder()) { + return; + } + final boolean collidingHorizontally = this.data.getPositionProcessor().isCollidingHorizontally(); + final boolean collidingVertically = this.data.getPositionProcessor().isCollidingVertically(); + if (!collidingHorizontally) { + if (!collidingVertically) { + final VelocityProcessor.VelocitySnapshot snapshot = this.data.getVelocityProcessor().getSnapshot(); + if (snapshot == null) { + return; + } + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double lastDeltaXZ = this.data.getPositionProcessor().getLastDeltaXZ(); + final double velocityXZ = MathUtil.hypot(snapshot.getVelocity().getX(), snapshot.getVelocity().getZ()); + final int velocityTicks = this.data.getVelocityProcessor().getTransactionFlyingTicks(); + if (velocityTicks > 50) { + return; + } + final boolean sprinting = this.data.getActionProcessor().isSprinting(); + final double minimum = (sprinting || this.lastSprint) ? 0.275 : 0.7; + final boolean exempt = this.isExempt(ExemptType.COLLIDING_VERTICALLY, ExemptType.LIQUID, ExemptType.FROZEN, ExemptType.CHUNK, ExemptType.LEVITATION, ExemptType.FALL_DAMAGE, ExemptType.ENDER_PEARL, ExemptType.WEB, ExemptType.VOID, ExemptType.SLOW_FALLING, ExemptType.BUKKIT_VELOCITY, ExemptType.ENDER_PEARL, ExemptType.TRAPDOOR, ExemptType.SOUL_SAND, ExemptType.SLIME, ExemptType.COMBO_MODE, ExemptType.PLACED_WEB, ExemptType.FLIGHT, ExemptType.ATTRIBUTE_MODIFIER, ExemptType.NETHERITE_ARMOR, ExemptType.FULLY_STUCK, ExemptType.FISHING_ROD, ExemptType.PARTIALLY_STUCK, ExemptType.VEHICLE, ExemptType.MYTHIC_MOB, ExemptType.ELYTRA, ExemptType.SWEET_BERRIES); + if (velocityXZ < 0.01 || exempt) { + return; + } + switch(velocityTicks) { + case 1: + double ratio = deltaXZ / velocityXZ; + if (ratio < minimum) { + if (++this.firstTickBuffer > this.MAX_BUFFER) { + this.fail("tick=1 percent=" + ratio * 100.0D + "% s=" + sprinting + " ls=" + this.lastSprint + " deltaXZ=" + deltaXZ + " velocityXZ=" + velocityXZ); + } + } else if (this.firstTickBuffer > 0.0D) { + this.firstTickBuffer -= this.BUFFER_DECAY; + } + break; + case 2: + double ratio2 = deltaXZ / (lastDeltaXZ * (double)0.91F * (double)0.6F); + double minimum2 = !sprinting && !this.lastSprint ? 0.32D : 0.1D; + if (ratio2 < minimum2) { + if (++this.secondTickBuffer > this.MAX_BUFFER) { + this.fail("tick=2 percent=" + ratio2 * 100.0D + "% s=" + sprinting + " ls=" + this.lastSprint + " deltaXZ=" + deltaXZ + " velocityXZ=" + velocityXZ); + } + } else if (this.secondTickBuffer > 0.0D) { + this.secondTickBuffer -= this.BUFFER_DECAY; + } + break; + case 3: + double ratio3 = deltaXZ / (lastDeltaXZ * (double)0.91F); + double minimum3 = !sprinting && !this.lastSprint ? 0.25D : 0.1D; + if (ratio3 < minimum3) { + if (++this.thirdTickBuffer > this.MAX_BUFFER) { + this.fail("tick=3 percent=" + ratio3 * 100.0D + "% s=" + sprinting + " ls=" + this.lastSprint + " deltaXZ=" + deltaXZ + " velocityXZ=" + velocityXZ); + } + } else if (this.thirdTickBuffer > 0.0D) { + this.thirdTickBuffer -= this.BUFFER_DECAY; + } + break; + case 4: + double ratio4 = deltaXZ / (lastDeltaXZ * (double)0.91F); + double minimum4 = !sprinting && !this.lastSprint ? 0.25D : 0.1D; + if (ratio4 < minimum4) { + if (++this.fourthTickBuffer > this.MAX_BUFFER) { + this.fail("tick=4 percent=" + ratio4 * 100.0D + "% s=" + sprinting + " ls=" + this.lastSprint + " deltaXZ=" + deltaXZ + " velocityXZ=" + velocityXZ); + } + } else if (this.fourthTickBuffer > 0.0D) { + this.fourthTickBuffer -= this.BUFFER_DECAY; + } + } + this.lastSprint = sprinting; + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/combat/velocity/VelocityD.java b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/velocity/VelocityD.java new file mode 100644 index 0000000..800282b --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/combat/velocity/VelocityD.java @@ -0,0 +1,249 @@ +package me.frep.vulcan.spigot.check.impl.combat.velocity; + +import org.bukkit.Location; +import me.frep.vulcan.spigot.util.type.Pair; +import me.frep.vulcan.spigot.data.processor.VelocityProcessor; +import io.github.retrooper.packetevents.packetwrappers.play.in.flying.WrappedPacketInFlying; +import io.github.retrooper.packetevents.packetwrappers.play.in.useentity.WrappedPacketInUseEntity; +import me.frep.vulcan.spigot.util.nms.MathHelper; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Velocity", type = 'D', complexType = "Horizontal", description = "Horizontal velocity modifications.", experimental = true) +public class VelocityD extends AbstractCheck +{ + private final float LAND_MOVEMENT_FACTOR; + private final double MINIMUM_MOVEMENT; + private static final float SPEED_IN_AIR = 0.02f; + private static final float FRICTION = 0.6f; + private boolean hadPosition; + private boolean hadHadPosition; + private int attacks; + + public VelocityD(final PlayerData data) { + super(data); + this.LAND_MOVEMENT_FACTOR = (this.data.is1_13() ? 0.21600002f : 0.16277136f); + this.MINIMUM_MOVEMENT = (this.data.is1_9() ? 0.003 : 0.005); + this.hadPosition = false; + this.hadHadPosition = false; + this.attacks = 0; + } + + @Override + public void handle(final Packet packet) { + if (packet.isFlying() && !this.teleporting()) { + final boolean push = this.data.getActionProcessor().getSincePushTicks() < 20; + if (push || this.data.getPositionProcessor().isNearBorder()) { + return; + } + final WrappedPacketInFlying wrapper = this.data.getFlyingWrapper(); + final VelocityProcessor velocityProcessor = this.data.getVelocityProcessor(); + final int sinceVelocityTicks = velocityProcessor.getTransactionFlyingTicks(); + final boolean velocity = sinceVelocityTicks == 1; + final boolean exempt = this.isExempt(ExemptType.SLOW_FALLING, ExemptType.LEVITATION, ExemptType.COLLIDING_VERTICALLY, ExemptType.COLLIDING_HORIZONTALLY, ExemptType.ELYTRA, ExemptType.GLIDING, ExemptType.RIPTIDE, ExemptType.ENTITY_COLLISION, ExemptType.SWEET_BERRIES, ExemptType.LIQUID, ExemptType.CLIMBABLE, ExemptType.ICE, ExemptType.SOUL_SAND, ExemptType.HONEY, ExemptType.ATTRIBUTE_MODIFIER, ExemptType.CAKE, ExemptType.NETHERITE_ARMOR, ExemptType.FROZEN, ExemptType.CHUNK, ExemptType.TRAPDOOR, ExemptType.DOOR, ExemptType.ILLEGAL_BLOCK, ExemptType.VEHICLE, ExemptType.DOLPHINS_GRACE, ExemptType.MYTHIC_MOB, ExemptType.PLACED_WEB, ExemptType.FULLY_STUCK, ExemptType.PARTIALLY_STUCK, ExemptType.VOID, ExemptType.CAULDRON, ExemptType.BUKKIT_VELOCITY, ExemptType.WEB, ExemptType.WATERLOGGED, ExemptType.ENDER_PEARL, ExemptType.FISHING_ROD, ExemptType.RESPAWN, ExemptType.DRAGON_DAMAGE, ExemptType.TELEPORT, ExemptType.DEATH, ExemptType.WORLD_CHANGE, ExemptType.FLIGHT); + if (sinceVelocityTicks <= 6 && !exempt) { + if (this.data.getPositionProcessor().getSinceCollidingVerticallyTicks() >= 3) { + final VelocityProcessor.VelocitySnapshot snapshot = this.data.getVelocityProcessor().getSnapshot(); + if (snapshot == null) { + return; + } + if (snapshot.getVelocity().getX() >= 0.01 || snapshot.getVelocity().getY() >= 0.01 || snapshot.getVelocity().getZ() >= 0.01) { + float slipperiness = 0.91f; + float lastSlipperiness = 0.91f; + final boolean lastLastOnGround = this.data.getPositionProcessor().isLastLastClientOnGround(); + final boolean lastOnGround = this.data.getPositionProcessor().isLastClientOnGround(); + if (lastOnGround) { + slipperiness = 0.54600006f; + } + if (lastLastOnGround) { + lastSlipperiness = 0.54600006f; + } + double smallest = Double.MAX_VALUE; + for (int i = 0; i < 9; ++i) { + for (int sprintIter = 0; sprintIter < 2; ++sprintIter) { + for (int useItemIter = 0; useItemIter < 2; ++useItemIter) { + for (int slowdownIter = 0; slowdownIter < 2; ++slowdownIter) { + for (int jumpIter = 0; jumpIter < 2; ++jumpIter) { + final boolean sprinting = sprintIter == 0; + final boolean blocking = useItemIter == 0; + final boolean hitSlowdown = slowdownIter == 0; + final boolean jump = jumpIter == 0; + final Pair keyPresses = this.getKeyIndex(i); + float forward = keyPresses.getX(); + float strafe = keyPresses.getY(); + if (blocking) { + forward *= (float)0.2; + strafe *= (float)0.2; + } + if (this.data.getActionProcessor().isSneaking()) { + forward *= 0.3f; + strafe *= 0.3f; + } + forward *= 0.98f; + strafe *= 0.98f; + double motionX = velocity ? velocityProcessor.getVelocityX() : this.data.getPositionProcessor().getLastDeltaX(); + double motionY = velocity ? velocityProcessor.getVelocityY() : this.data.getPositionProcessor().getLastDeltaY(); + double motionZ = velocity ? velocityProcessor.getVelocityZ() : this.data.getPositionProcessor().getLastDeltaZ(); + double moveSpeed = this.getAttributeSpeed(this.data); + if (sprinting) { + moveSpeed += moveSpeed * 0.30000001192092896; + } + final float moveSpeedMultiplier = this.LAND_MOVEMENT_FACTOR / (slipperiness * slipperiness * slipperiness); + float moveFlyingFriction; + if (lastOnGround) { + moveFlyingFriction = (float)moveSpeed * moveSpeedMultiplier; + } + else { + moveFlyingFriction = (float)(sprinting ? 0.025999999418854714 : 0.019999999552965164); + } + if (!this.data.is1_9() && this.attacks > 0 && hitSlowdown) { + motionX *= 0.6; + motionZ *= 0.6; + } + if (!velocity) { + motionY -= 0.08; + motionX *= lastSlipperiness; + motionY *= 0.9800000190734863; + motionZ *= lastSlipperiness; + } + if (Math.abs(motionX) < this.MINIMUM_MOVEMENT) { + motionX = 0.0; + } + if (Math.abs(motionY) < this.MINIMUM_MOVEMENT) { + motionY = 0.0; + } + if (Math.abs(motionZ) < this.MINIMUM_MOVEMENT) { + motionZ = 0.0; + } + if (jump && lastOnGround) { + motionY = 0.41999998688697815; + if (this.data.getActionProcessor().isHasJumpBoost()) { + motionY += this.data.getActionProcessor().getJumpBoostAmplifier() * 0.1f; + } + if (sprinting) { + final float f = this.data.getRotationProcessor().getYaw() * 0.017453292f; + motionX -= MathHelper.sin(f) * 0.2f; + motionZ += MathHelper.cos(f) * 0.2f; + } + } + float diagonal = strafe * strafe + forward * forward; + double moveFlyingFactorX = 0.0; + double moveFlyingFactorZ = 0.0; + if (diagonal > 1.0E-4f) { + diagonal = MathHelper.sqrt_float(diagonal); + if (diagonal < 1.0f) { + diagonal = 1.0f; + } + diagonal = moveFlyingFriction / diagonal; + final float flyingStrafe = strafe * diagonal; + final float flyingForward = forward * diagonal; + final float rotationYaw = this.data.getRotationProcessor().getYaw(); + final float f2 = MathHelper.sin(rotationYaw * 3.1415927f / 180.0f); + final float f3 = MathHelper.cos(rotationYaw * 3.1415927f / 180.0f); + final double factorX = flyingStrafe * f3 - flyingForward * f2; + final double factorZ = flyingForward * f3 + flyingStrafe * f2; + moveFlyingFactorX = factorX; + moveFlyingFactorZ = factorZ; + } + motionX += moveFlyingFactorX; + motionZ += moveFlyingFactorZ; + final Location predicted = this.data.getPositionProcessor().getFrom().clone().add(motionX, 0.0, motionZ); + predicted.setY(0.0); + final Location to = this.data.getPositionProcessor().getTo().clone(); + to.setY(0.0); + final double distance = to.distanceSquared(predicted); + if (distance < smallest) { + smallest = distance; + } + } + } + } + } + } + if (smallest <= 10.0) { + double threshold = 5.0E-6 + ((this.hadPosition && this.hadHadPosition) ? 0.0 : 0.001); + if (this.data.is1_9()) { + threshold += 0.001; + } + if (smallest > threshold) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("offset=" + smallest + " threshold=" + threshold + " tick=" + sinceVelocityTicks); + } + } + else { + this.decayBuffer(); + } + } + } + } + } + this.hadHadPosition = this.hadPosition; + this.hadPosition = wrapper.isMoving(); + this.attacks = 0; + } + else if (packet.isUseEntity()) { + final WrappedPacketInUseEntity wrapper2 = this.data.getUseEntityWrapper(); + if (wrapper2.getAction() == WrappedPacketInUseEntity.EntityUseAction.ATTACK) { + ++this.attacks; + } + } + } + + private Pair getKeyIndex(final int index) { + float strafeForward = 0.0f; + float strafeSideways = 0.0f; + switch (index) { + case 0: { + strafeForward = 1.0f; + break; + } + case 1: { + strafeForward = 1.0f; + strafeSideways = -1.0f; + break; + } + case 2: { + strafeSideways = -1.0f; + break; + } + case 3: { + strafeForward = -1.0f; + strafeSideways = -1.0f; + break; + } + case 4: { + strafeForward = -1.0f; + break; + } + case 5: { + strafeForward = -1.0f; + strafeSideways = 1.0f; + break; + } + case 6: { + strafeSideways = 1.0f; + break; + } + case 7: { + strafeForward = 1.0f; + strafeSideways = 1.0f; + break; + } + case 8: { + strafeForward = 0.0f; + strafeSideways = 0.0f; + break; + } + } + return new Pair(strafeForward, strafeSideways); + } + + public float getAttributeSpeed(final PlayerData data) { + double attributeSpeed = data.getActionProcessor().getGenericMovementSpeed(); + attributeSpeed += data.getActionProcessor().getSpeedAmplifier() * 0.2 * attributeSpeed; + return (float)attributeSpeed; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/antilevitation/AntiLevitationA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/antilevitation/AntiLevitationA.java new file mode 100644 index 0000000..efcd288 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/antilevitation/AntiLevitationA.java @@ -0,0 +1,40 @@ +package me.frep.vulcan.spigot.check.impl.movement.antilevitation; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Anti Levitation", type = 'A', complexType = "Ignore", description = "Ignored Levitation effect.") +public class AntiLevitationA extends AbstractCheck +{ + public AntiLevitationA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting()) { + if (ServerUtil.isLowerThan1_9() || this.data.getActionProcessor().getLevitationAmplifier() < 0) { + return; + } + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final boolean mathOnGround = this.data.getPositionProcessor().isMathematicallyOnGround(); + final boolean onGround = this.data.getPositionProcessor().isClientOnGround(); + final boolean levitation = this.data.getActionProcessor().isHasLevitation(); + final boolean touchingAir = this.data.getPositionProcessor().isTouchingAir(); + final boolean invalid = levitation && (onGround || deltaY < 0.0 || (!touchingAir && mathOnGround)); + final boolean exempt = this.isExempt(ExemptType.SCAFFOLDING, ExemptType.VOID, ExemptType.COLLIDING_VERTICALLY, ExemptType.TRAPDOOR, ExemptType.BED, ExemptType.SLIME, ExemptType.HONEY, ExemptType.VELOCITY, ExemptType.RIPTIDE, ExemptType.BUKKIT_VELOCITY, ExemptType.JOINED, ExemptType.SWIMMING, ExemptType.CHUNK, ExemptType.JOINED_CHUNK_LOAD, ExemptType.WEB, ExemptType.SLEEPING, ExemptType.DEATH, ExemptType.FROZEN, ExemptType.BLOCK_PLACE, ExemptType.BLOCK_BREAK, ExemptType.ATTRIBUTE_MODIFIER, ExemptType.FULLY_STUCK, ExemptType.PARTIALLY_STUCK, ExemptType.WORLD_CHANGE, ExemptType.VEHICLE, ExemptType.BOAT, ExemptType.GLIDING, ExemptType.SLOW_FALLING, ExemptType.BUBBLE_COLUMN, ExemptType.SPECTATOR, ExemptType.DOLPHINS_GRACE, ExemptType.SHULKER_BOX) || this.data.getPositionProcessor().isExemptTeleport() || this.data.getPositionProcessor().isExemptClimbable() || this.data.getPositionProcessor().isExemptFlight() || this.data.getPositionProcessor().isExemptCreative() || this.data.getPositionProcessor().isExemptLiquid() || this.data.getPositionProcessor().isExemptElytra(); + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaY=" + deltaY + " onGround=" + onGround + " amplifier=" + this.data.getActionProcessor().getLevitationAmplifier()); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/boatfly/BoatFlyA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/boatfly/BoatFlyA.java new file mode 100644 index 0000000..bf0e5d5 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/boatfly/BoatFlyA.java @@ -0,0 +1,58 @@ +package me.frep.vulcan.spigot.check.impl.movement.boatfly; + +import org.bukkit.plugin.Plugin; +import org.bukkit.Bukkit; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.entity.Boat; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Boat Fly", type = 'A', complexType = "Vertical", description = "Moving upwards in a boat.") +public class BoatFlyA extends AbstractCheck +{ + public BoatFlyA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isVehicleMove()) { + if (ServerUtil.isLowerThan1_9()) { + return; + } + final boolean boat = this.data.getPlayer().getVehicle() != null && this.data.getPlayer().getVehicle() instanceof Boat; + final int vehicleTicks = this.data.getPositionProcessor().getVehicleTicks(); + if (boat && vehicleTicks > 10) { + final Boat boatEntity = (Boat)this.data.getPlayer().getVehicle(); + final double deltaY = this.data.getPositionProcessor().getVehicleDeltaY(); + final boolean liquid = this.data.getPositionProcessor().getSinceVehicleNearLiquidTicks() < 100; + final boolean slime = this.data.getPositionProcessor().getSinceVehicleNearSlimeTicks() < 100; + final boolean bubbleColumn = this.data.getPositionProcessor().getSinceVehicleNearBubbleColumnTicks() < 100; + final boolean piston = this.data.getPositionProcessor().getSinceVehicleNearPistonTicks() < 50; + final boolean bed = this.data.getPositionProcessor().getSinceVehicleNearBedTicks() < 40; + final boolean touchingAir = this.data.getPositionProcessor().isVehicleInAir(); + if (ServerUtil.isHigherThan1_13() && !boatEntity.hasGravity()) { + return; + } + if (Vulcan.INSTANCE.getFishingRodPulledBoats().containsKey(boatEntity.getEntityId())) { + return; + } + if (deltaY > 0.01 && !slime && !liquid && !bubbleColumn && !piston && !bed && touchingAir) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaY=" + deltaY); + if (Config.BOAT_FLY_A_KICKOUT) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().leaveVehicle()); + } + } + } + else { + this.decayBuffer(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/boatfly/BoatFlyB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/boatfly/BoatFlyB.java new file mode 100644 index 0000000..4915786 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/boatfly/BoatFlyB.java @@ -0,0 +1,65 @@ +package me.frep.vulcan.spigot.check.impl.movement.boatfly; + +import org.bukkit.plugin.Plugin; +import org.bukkit.Bukkit; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.entity.Boat; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Boat Fly", type = 'B', complexType = "Vertical", description = "Moving too quickly horizontally.") +public class BoatFlyB extends AbstractCheck +{ + public BoatFlyB(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isVehicleMove()) { + if (ServerUtil.isLowerThan1_9()) { + return; + } + final boolean boat = this.data.getPlayer().getVehicle() instanceof Boat; + final int vehicleTicks = this.data.getPositionProcessor().getVehicleTicks(); + final String spigotID = Vulcan.INSTANCE.getSpigot(); + if (vehicleTicks > 10 && boat) { + final Boat boatEntity = (Boat)this.data.getPlayer().getVehicle(); + final double deltaXZ = this.data.getPositionProcessor().getVehicleDeltaXZ(); + final double deltaY = this.data.getPositionProcessor().getVehicleDeltaY(); + final boolean ice = this.data.getPositionProcessor().getSinceVehicleNearIceTicks() < 100; + final boolean liquid = this.data.getPositionProcessor().getSinceVehicleNearLiquidTicks() < 100; + final boolean slime = this.data.getPositionProcessor().getSinceVehicleNearSlimeTicks() < 100; + final boolean bubbleColumn = this.data.getPositionProcessor().getSinceVehicleNearBubbleColumnTicks() < 100; + final int boatsAround = this.data.getPositionProcessor().getBoatsAround(); + if (ServerUtil.isHigherThan1_13() && !boatEntity.hasGravity()) { + return; + } + if (Vulcan.INSTANCE.getFishingRodPulledBoats().containsKey(boatEntity.getEntityId())) { + return; + } + double max = 0.25; + if (this.isExempt(ExemptType.WATERLOGGED)) { + max += 0.1; + } + final boolean invalid = deltaXZ > max && deltaY > -0.05 && !liquid && !slime && !bubbleColumn && !ice; + if (invalid && boatsAround == 1) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaXZ=" + deltaXZ + " deltaY=" + deltaY); + if (Config.BOAT_FLY_B_KICKOUT) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().leaveVehicle()); + } + } + } + else { + this.decayBuffer(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/boatfly/BoatFlyC.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/boatfly/BoatFlyC.java new file mode 100644 index 0000000..16b73cf --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/boatfly/BoatFlyC.java @@ -0,0 +1,59 @@ +package me.frep.vulcan.spigot.check.impl.movement.boatfly; + +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.entity.Boat; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Boat Fly", type = 'C', complexType = "Hover", description = "Hovering in a boat.") +public class BoatFlyC extends AbstractCheck +{ + public BoatFlyC(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isVehicleMove()) { + if (ServerUtil.isLowerThan1_9()) { + return; + } + final boolean boat = this.data.getPlayer().getVehicle() instanceof Boat; + final int vehicleTicks = this.data.getPositionProcessor().getVehicleTicks(); + if (vehicleTicks > 10 && boat) { + final Boat boatEntity = (Boat)this.data.getPlayer().getVehicle(); + if (Vulcan.INSTANCE.getFishingRodPulledBoats().containsKey(boatEntity.getEntityId())) { + return; + } + final double deltaY = this.data.getPositionProcessor().getVehicleDeltaY(); + final double lastDeltaY = this.data.getPositionProcessor().getLastVehicleDeltaY(); + final double acceleration = Math.abs(deltaY - lastDeltaY); + final int airTicks = this.data.getPositionProcessor().getVehicleAirTicks(); + final boolean invalid = deltaY > -0.05 && acceleration < 0.025 && airTicks > 5; + if (this.data.getPositionProcessor().isVehicleNearEntity()) { + return; + } + if (ServerUtil.isHigherThan1_13() && !boatEntity.hasGravity()) { + return; + } + final boolean ice = this.data.getPositionProcessor().getSinceVehicleNearIceTicks() < 50; + final boolean liquid = this.data.getPositionProcessor().getSinceVehicleNearLiquidTicks() < 50; + final boolean slime = this.data.getPositionProcessor().getSinceVehicleNearSlimeTicks() < 50; + final boolean bubbleColumn = this.data.getPositionProcessor().getSinceVehicleNearBubbleColumnTicks() < 50; + final boolean piston = this.data.getPositionProcessor().getSinceVehicleNearPistonTicks() < 50; + final int boatsAround = this.data.getPositionProcessor().getBoatsAround(); + if (invalid && !ice && !liquid && !slime && !bubbleColumn && !piston && boatsAround == 1) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("accel=" + acceleration + " deltaY=" + deltaY); + } + } + else { + this.decayBuffer(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraA.java new file mode 100644 index 0000000..df6dc86 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraA.java @@ -0,0 +1,37 @@ +package me.frep.vulcan.spigot.check.impl.movement.elytra; + +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Elytra", type = 'A', complexType = "Limit", description = "Gliding too quickly on X/Z axis.") +public class ElytraA extends AbstractCheck +{ + public ElytraA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting()) { + if (ServerUtil.isLowerThan1_9() || !this.data.getActionProcessor().isBukkitGliding()) { + return; + } + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final boolean exempt = this.isExempt(ExemptType.RIPTIDE, ExemptType.TELEPORT, ExemptType.WORLD_CHANGE, ExemptType.DEATH, ExemptType.ENDER_PEARL, ExemptType.CHORUS_FRUIT, ExemptType.SERVER_POSITION_FAST, ExemptType.DRAGON_DAMAGE, ExemptType.BUKKIT_VELOCITY, ExemptType.DOLPHINS_GRACE) || this.data.getVelocityProcessor().getSinceHighVelocityTicks() < 50 || this.data.getPositionProcessor().getSinceFuckingEntityTicks() < 200; + final boolean riptide = this.data.getPositionProcessor().getSinceRiptideTicks() < 400; + if (deltaXZ > Config.ELYTRA_A_MAX_SPEED && !exempt && !riptide) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaXZ=" + deltaXZ); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraB.java new file mode 100644 index 0000000..f341f29 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraB.java @@ -0,0 +1,42 @@ +package me.frep.vulcan.spigot.check.impl.movement.elytra; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Elytra", type = 'B', complexType = "Acceleration", description = "Invalid Y-Axis change.") +public class ElytraB extends AbstractCheck +{ + public ElytraB(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition()) { + if (ServerUtil.isLowerThan1_9() || !this.data.getActionProcessor().isBukkitGliding()) { + return; + } + final int glidingTicks = this.data.getPositionProcessor().getGlidingTicks(); + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double lastDeltaXZ = this.data.getPositionProcessor().getLastDeltaXZ(); + final double accelerationXZ = Math.abs(deltaXZ - lastDeltaXZ); + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final double lastDeltaY = this.data.getPositionProcessor().getLastDeltaY(); + final double accelerationY = Math.abs(deltaY - lastDeltaY); + final boolean exempt = this.isExempt(ExemptType.FIREWORK, ExemptType.LIQUID); + final boolean invalid = glidingTicks > 5 && glidingTicks < 400 && accelerationXZ < 1.0E-10 && accelerationY < 1.0E-10 && deltaXZ > 1.0; + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + glidingTicks + " deltaXZ=" + deltaXZ + " deltaY=" + deltaY + " accelXZ=" + accelerationXZ + " accelY=" + accelerationY); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraC.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraC.java new file mode 100644 index 0000000..6f1d7e2 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraC.java @@ -0,0 +1,42 @@ +package me.frep.vulcan.spigot.check.impl.movement.elytra; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Elytra", type = 'C', complexType = "Acceleration", description = "Invalid acceleration.") +public class ElytraC extends AbstractCheck +{ + public ElytraC(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition()) { + if (ServerUtil.isLowerThan1_9() || !this.data.getActionProcessor().isBukkitGliding()) { + return; + } + final int glidingTicks = this.data.getPositionProcessor().getGlidingTicks(); + final int airTicks = this.data.getPositionProcessor().getServerAirTicks(); + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double lastDeltaXZ = this.data.getPositionProcessor().getLastDeltaXZ(); + final boolean gliding = PlayerUtil.isGliding(this.data.getPlayer()); + final boolean exempt = this.isExempt(ExemptType.FIREWORK, ExemptType.EXPLOSION, ExemptType.RIPTIDE, ExemptType.DRAGON_DAMAGE, ExemptType.FLIGHT, ExemptType.SLIME) || this.data.getVelocityProcessor().getSinceHighVelocityTicks() < 50; + final double acceleration = deltaXZ - lastDeltaXZ; + if (glidingTicks > 3 && airTicks > 3 && gliding && !exempt && acceleration > 0.035 && deltaY > -0.6) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("accel=" + acceleration + " deltaXZ=" + deltaXZ + " deltaY=" + deltaY); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraF.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraF.java new file mode 100644 index 0000000..81a745d --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraF.java @@ -0,0 +1,43 @@ +package me.frep.vulcan.spigot.check.impl.movement.elytra; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import io.github.retrooper.packetevents.packetwrappers.play.in.entityaction.WrappedPacketInEntityAction; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Elytra", type = 'F', complexType = "Packet", description = "Sending Elytra packets too quickly.") +public class ElytraF extends AbstractCheck +{ + private long lastGlide; + + public ElytraF(final PlayerData data) { + super(data); + this.lastGlide = 0L; + } + + @Override + public void handle(final Packet packet) { + if (packet.isEntityAction() && !this.teleporting()) { + if (ServerUtil.isLowerThan1_9()) { + return; + } + final WrappedPacketInEntityAction wrapper = this.data.getEntityActionWrapper(); + if (wrapper.getAction() == WrappedPacketInEntityAction.PlayerAction.START_FALL_FLYING) { + final long delay = System.currentTimeMillis() - this.lastGlide; + final boolean exempt = this.isExempt(ExemptType.FAST); + if (delay < 110L && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("delay=" + delay); + } + } + else { + this.decayBuffer(); + } + this.lastGlide = System.currentTimeMillis(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraG.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraG.java new file mode 100644 index 0000000..6cce1a8 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraG.java @@ -0,0 +1,39 @@ +package me.frep.vulcan.spigot.check.impl.movement.elytra; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Elytra", type = 'G', complexType = "Acceleration", description = "Invalid acceleration.") +public class ElytraG extends AbstractCheck +{ + public ElytraG(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition()) { + if (ServerUtil.isLowerThan1_9() || !this.data.getActionProcessor().isBukkitGliding()) { + return; + } + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double lastDeltaXZ = this.data.getPositionProcessor().getLastDeltaXZ(); + final double acceleration = deltaXZ - lastDeltaXZ; + final boolean invalid = acceleration > 0.03 && deltaY > -0.5 && deltaXZ > 0.65; + final boolean exempt = this.isExempt(ExemptType.FIREWORK, ExemptType.EXPLOSION, ExemptType.RIPTIDE, ExemptType.DRAGON_DAMAGE, ExemptType.FLIGHT, ExemptType.VELOCITY, ExemptType.SLIME, ExemptType.DOLPHINS_GRACE); + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("accel=" + acceleration + " deltaXZ=" + deltaXZ + " deltaY=" + deltaY); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraI.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraI.java new file mode 100644 index 0000000..5d948f7 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraI.java @@ -0,0 +1,36 @@ +package me.frep.vulcan.spigot.check.impl.movement.elytra; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Elytra", type = 'I', complexType = "Motion", description = "Invalid motion.") +public class ElytraI extends AbstractCheck +{ + public ElytraI(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting()) { + if (ServerUtil.isLowerThan1_9() || !this.data.getActionProcessor().isBukkitGliding()) { + return; + } + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double modulo = 0.1 % (deltaXZ % 0.1); + final boolean exempt = this.isExempt(ExemptType.FIREWORK, ExemptType.EXPLOSION, ExemptType.RIPTIDE, ExemptType.DRAGON_DAMAGE, ExemptType.FLIGHT, ExemptType.VELOCITY, ExemptType.LIQUID); + if (modulo < 1.0E-8 && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaXZ=" + deltaXZ); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraK.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraK.java new file mode 100644 index 0000000..3d4b65e --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraK.java @@ -0,0 +1,41 @@ +package me.frep.vulcan.spigot.check.impl.movement.elytra; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Elytra", type = 'K', complexType = "Acceleration", description = "Accelerating while ascending.") +public class ElytraK extends AbstractCheck +{ + public ElytraK(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting()) { + if (ServerUtil.isLowerThan1_9() || !this.data.getActionProcessor().isBukkitGliding()) { + return; + } + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double lastDeltaXZ = this.data.getPositionProcessor().getLastDeltaXZ(); + final double acceleration = deltaXZ - lastDeltaXZ; + final int glidingTicks = this.data.getPositionProcessor().getGlidingTicks(); + final boolean ascending = deltaY > 0.0; + final boolean accelerating = acceleration > 0.005; + final boolean exempt = this.isExempt(ExemptType.FIREWORK, ExemptType.EXPLOSION, ExemptType.RIPTIDE, ExemptType.DRAGON_DAMAGE, ExemptType.FLIGHT, ExemptType.VELOCITY, ExemptType.SLIME, ExemptType.DOLPHINS_GRACE, ExemptType.LIQUID); + if (deltaXZ > 0.3 && ascending && accelerating && !exempt && glidingTicks > 5) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaXZ=" + deltaXZ + " accel=" + accelerating + " ticks=" + glidingTicks); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraL.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraL.java new file mode 100644 index 0000000..cfd7028 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraL.java @@ -0,0 +1,42 @@ +package me.frep.vulcan.spigot.check.impl.movement.elytra; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Elytra", type = 'L', complexType = "Ascending", description = "Moving up wrongly.") +public class ElytraL extends AbstractCheck +{ + public ElytraL(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting()) { + if (!this.data.getActionProcessor().isBukkitGliding()) { + return; + } + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final float pitch = this.data.getRotationProcessor().getPitch(); + final boolean exempt = this.isExempt(ExemptType.DRAGON_DAMAGE, ExemptType.EXPLOSION, ExemptType.FIREWORK, ExemptType.TELEPORT, ExemptType.FISHING_ROD, ExemptType.RIPTIDE, ExemptType.BUBBLE_COLUMN, ExemptType.LIQUID, ExemptType.SLIME, ExemptType.PISTON, ExemptType.BUKKIT_VELOCITY, ExemptType.WORLD_CHANGE, ExemptType.SWIMMING, ExemptType.BED, ExemptType.LEVITATION, ExemptType.FLIGHT) || this.data.getPositionProcessor().getSinceFuckingEntityTicks() < 200 || this.data.getVelocityProcessor().getSinceHighVelocityTicks() < 50; + double max = 1.35; + if (this.data.getActionProcessor().getJumpBoostAmplifier() > 0) { + max += this.data.getActionProcessor().getJumpBoostAmplifier() * 0.1; + } + final int riptideTicks = this.data.getPositionProcessor().getSinceRiptideTicks(); + final boolean riptide = riptideTicks < 400; + final boolean invalid = deltaY > max && pitch > -25.0f; + if (invalid && !exempt && !riptide) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaY=" + deltaY + " pitch=" + pitch + " rt=" + riptideTicks); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraM.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraM.java new file mode 100644 index 0000000..3cb0ebc --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/elytra/ElytraM.java @@ -0,0 +1,37 @@ +package me.frep.vulcan.spigot.check.impl.movement.elytra; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Elytra", type = 'M', complexType = "Ascending", description = "Invalid ascension pattern.") +public class ElytraM extends AbstractCheck +{ + public ElytraM(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting()) { + if (!this.data.getActionProcessor().isBukkitGliding()) { + return; + } + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + if (Math.abs(deltaY) > 0.01) { + final double modulo = 0.01 % (deltaY % 0.01); + final boolean exempt = this.isExempt(ExemptType.FLIGHT, ExemptType.SLIME, ExemptType.SLOW_FALLING, ExemptType.LEVITATION, ExemptType.LIQUID, ExemptType.BUBBLE_COLUMN, ExemptType.LIQUID, ExemptType.RIPTIDE, ExemptType.BUKKIT_VELOCITY); + if (modulo < 1.0E-8 && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaY=" + deltaY + " m=" + modulo); + } + } + else { + this.decayBuffer(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/entityflight/EntityFlightA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/entityflight/EntityFlightA.java new file mode 100644 index 0000000..8d4e514 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/entityflight/EntityFlightA.java @@ -0,0 +1,105 @@ +package me.frep.vulcan.spigot.check.impl.movement.entityflight; + +import org.bukkit.plugin.Plugin; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.Bukkit; +import me.frep.vulcan.spigot.config.Config; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.entity.Donkey; +import org.bukkit.entity.Pig; +import org.bukkit.entity.Horse; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Entity Flight", type = 'A', complexType = "Ascension", description = "Ascending while riding an entity.") +public class EntityFlightA extends AbstractCheck +{ + public EntityFlightA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isVehicleMove()) { + if (ServerUtil.isLowerThan1_9()) { + return; + } + if (this.data.getPositionProcessor().getVehicleY() < 0.0) { + return; + } + final boolean vehicleHorse = this.data.getPlayer().getVehicle() instanceof Horse; + final boolean pig = this.data.getPlayer().getVehicle() instanceof Pig; + final boolean donkey = ServerUtil.isHigherThan1_9() && this.data.getPlayer().getVehicle() instanceof Donkey; + final boolean liquid = this.data.getPositionProcessor().getSinceVehicleNearLiquidTicks() < 100; + final boolean slime = this.data.getPositionProcessor().getSinceVehicleNearSlimeTicks() < 100; + final boolean bubbleColumn = this.data.getPositionProcessor().getSinceVehicleNearBubbleColumnTicks() < 100; + final int vehicleTicks = this.data.getPositionProcessor().getVehicleTicks(); + final int airTicks = this.data.getPositionProcessor().getVehicleAirTicks(); + final double deltaY = this.data.getPositionProcessor().getVehicleDeltaY(); + final boolean invalid = airTicks > 30 && deltaY > 0.0 && !liquid && !slime && !bubbleColumn && vehicleTicks > 5; + if (vehicleHorse) { + final Horse horse = (Horse)this.data.getPlayer().getVehicle(); + if (horse.isLeashed()) { + return; + } + if (ServerUtil.isHigherThan1_13() && horse.hasPotionEffect(PotionEffectType.LEVITATION)) { + return; + } + if (invalid) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("[Horse] deltaY=" + deltaY + " ticks=" + airTicks); + if (Config.ENTITY_FLIGHT_A_KICKOUT) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().leaveVehicle()); + } + } + } + else { + this.decayBuffer(); + } + } + else if (pig) { + final Pig pigg = (Pig)this.data.getPlayer().getVehicle(); + if (pigg.isLeashed()) { + return; + } + if (ServerUtil.isHigherThan1_13() && pigg.hasPotionEffect(PotionEffectType.LEVITATION)) { + return; + } + if (invalid) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("[Pig] deltaY=" + deltaY + " ticks=" + airTicks); + if (Config.ENTITY_FLIGHT_A_KICKOUT) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().leaveVehicle()); + } + } + } + else { + this.decayBuffer(); + } + } + else if (donkey) { + final Donkey donkey2 = (Donkey)this.data.getPlayer().getVehicle(); + if (donkey2.isLeashed()) { + return; + } + if (ServerUtil.isHigherThan1_13() && donkey2.hasPotionEffect(PotionEffectType.LEVITATION)) { + return; + } + if (invalid) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("[Pig] deltaY=" + deltaY + " ticks=" + airTicks); + if (Config.ENTITY_FLIGHT_A_KICKOUT) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().leaveVehicle()); + } + } + } + else { + this.decayBuffer(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/entityflight/EntityFlightB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/entityflight/EntityFlightB.java new file mode 100644 index 0000000..2497b53 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/entityflight/EntityFlightB.java @@ -0,0 +1,94 @@ +package me.frep.vulcan.spigot.check.impl.movement.entityflight; + +import org.bukkit.potion.PotionEffectType; +import org.bukkit.entity.Donkey; +import org.bukkit.entity.Pig; +import org.bukkit.entity.Horse; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Entity Flight", type = 'B', complexType = "Hover", description = "Hovering while riding an entity.") +public class EntityFlightB extends AbstractCheck +{ + public EntityFlightB(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isVehicleMove()) { + if (ServerUtil.isLowerThan1_9()) { + return; + } + if (this.data.getPositionProcessor().getVehicleY() < 0.0) { + return; + } + final boolean vehicleHorse = this.data.getPlayer().getVehicle() instanceof Horse; + final boolean pig = this.data.getPlayer().getVehicle() instanceof Pig; + final boolean donkey = ServerUtil.isHigherThan1_9() && this.data.getPlayer().getVehicle() instanceof Donkey; + final boolean liquid = this.data.getPositionProcessor().getSinceVehicleNearLiquidTicks() < 100; + final boolean slime = this.data.getPositionProcessor().getSinceVehicleNearSlimeTicks() < 100; + final boolean bubbleColumn = this.data.getPositionProcessor().getSinceVehicleNearBubbleColumnTicks() < 100; + final int vehicleTicks = this.data.getPositionProcessor().getVehicleTicks(); + final int airTicks = this.data.getPositionProcessor().getVehicleAirTicks(); + final double deltaY = this.data.getPositionProcessor().getVehicleDeltaY(); + final double lastDeltaY = this.data.getPositionProcessor().getLastVehicleDeltaY(); + final double acceleration = Math.abs(deltaY - lastDeltaY); + final boolean invalid = airTicks > 30 && Math.abs(deltaY) < 5.0 && acceleration < 0.05 && !liquid && !slime && !bubbleColumn && vehicleTicks > 5 && deltaY > -1.5; + if (vehicleHorse) { + final Horse horse = (Horse)this.data.getPlayer().getVehicle(); + if (ServerUtil.isHigherThan1_13() && horse.hasPotionEffect(PotionEffectType.LEVITATION)) { + return; + } + if (horse.isLeashed()) { + return; + } + if (invalid) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("[Horse] deltaY=" + deltaY + " acceleration=" + acceleration + " ticks=" + vehicleTicks); + } + } + else { + this.decayBuffer(); + } + } + else if (pig) { + final Pig pigg = (Pig)this.data.getPlayer().getVehicle(); + if (ServerUtil.isHigherThan1_13() && pigg.hasPotionEffect(PotionEffectType.LEVITATION)) { + return; + } + if (pigg.isLeashed()) { + return; + } + if (invalid) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("[Pig] deltaY=" + deltaY + " acceleration=" + acceleration + " ticks=" + vehicleTicks); + } + } + else { + this.decayBuffer(); + } + } + else if (donkey) { + final Donkey donkeyy = (Donkey)this.data.getPlayer().getVehicle(); + if (ServerUtil.isHigherThan1_13() && donkeyy.hasPotionEffect(PotionEffectType.LEVITATION)) { + return; + } + if (donkeyy.isLeashed()) { + return; + } + if (invalid) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("[Pig] deltaY=" + deltaY + " acceleration=" + acceleration + " ticks=" + vehicleTicks); + } + } + else { + this.decayBuffer(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/entityspeed/EntitySpeedA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/entityspeed/EntitySpeedA.java new file mode 100644 index 0000000..410efa2 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/entityspeed/EntitySpeedA.java @@ -0,0 +1,307 @@ +package me.frep.vulcan.spigot.check.impl.movement.entityspeed; + +import org.bukkit.entity.TraderLlama; +import org.bukkit.entity.Llama; +import org.bukkit.entity.Strider; +import org.bukkit.entity.SkeletonHorse; +import org.bukkit.entity.ZombieHorse; +import org.bukkit.entity.Donkey; +import org.bukkit.entity.Mule; +import org.bukkit.plugin.Plugin; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.Bukkit; +import me.frep.vulcan.spigot.config.Config; +import org.bukkit.entity.LivingEntity; +import me.frep.vulcan.spigot.util.PlayerUtil; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.attribute.Attribute; +import org.bukkit.entity.Pig; +import org.bukkit.entity.Boat; +import org.bukkit.entity.Horse; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Entity Speed", type = 'A', complexType = "Limit", description = "Riding an entity too quickly.") +public class EntitySpeedA extends AbstractCheck +{ + public EntitySpeedA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isVehicleMove()) { + if (ServerUtil.isLowerThan1_9()) { + return; + } + final boolean vehicleHorse = this.data.getPlayer().getVehicle() instanceof Horse; + final boolean vehicleBoat = this.data.getPlayer().getVehicle() instanceof Boat; + final boolean vehiclePig = this.data.getPlayer().getVehicle() instanceof Pig; + final boolean liquid = this.data.getPositionProcessor().getSinceVehicleNearLiquidTicks() < 100; + final boolean slime = this.data.getPositionProcessor().getSinceVehicleNearSlimeTicks() < 100; + final boolean bubbleColumn = this.data.getPositionProcessor().getSinceVehicleNearBubbleColumnTicks() < 100; + final boolean ice = this.data.getPositionProcessor().getSinceVehicleNearIceTicks() < 100; + final boolean piston = this.data.getPositionProcessor().getSinceVehicleNearPistonTicks() < 40; + if (piston) { + return; + } + final int vehicleTicks = this.data.getPositionProcessor().getVehicleTicks(); + final double deltaXZ = this.data.getPositionProcessor().getVehicleDeltaXZ(); + final boolean ground = this.data.getPositionProcessor().getVehicleY() % 0.015625 == 0.0; + if (vehicleHorse) { + final Horse horse = (Horse)this.data.getPlayer().getVehicle(); + if (horse == null || horse.hasMetadata("PROCOSMETICS_ENTITY") || horse.isLeashed()) { + return; + } + double maxSpeed = horse.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getBaseValue() * 2.25 + 0.1; + if (horse.hasPotionEffect(PotionEffectType.SPEED)) { + maxSpeed += PlayerUtil.getSpeed(horse) * 0.15; + } + if (this.data.getActionProcessor().isHasSpeed()) { + maxSpeed += this.data.getActionProcessor().getSpeedAmplifier() * 0.065; + } + if (!ground) { + maxSpeed += 0.17499999701976776; + } + if (deltaXZ > maxSpeed && !ice && vehicleTicks > 10) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("[Horse] speed=" + deltaXZ + " maxSpeed=" + maxSpeed); + if (Config.ENTITY_SPEED_A_KICKOUT) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().leaveVehicle()); + } + } + } + else { + this.decayBuffer(); + } + } + else if (ServerUtil.isHigherThan1_12() && this.data.getPlayer().getVehicle() instanceof Mule) { + final Mule mule = (Mule)this.data.getPlayer().getVehicle(); + if (mule == null || mule.isLeashed()) { + return; + } + double maxSpeed = mule.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getBaseValue() * 2.25 + 0.1; + if (mule.hasPotionEffect(PotionEffectType.SPEED)) { + maxSpeed += PlayerUtil.getSpeed(mule) * 0.15; + } + if (this.data.getActionProcessor().isHasSpeed()) { + maxSpeed += this.data.getActionProcessor().getSpeedAmplifier() * 0.065; + } + if (!ground) { + maxSpeed += 0.17499999701976776; + } + if (deltaXZ > maxSpeed && !ice && vehicleTicks > 10) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("[Mule] speed=" + deltaXZ + " maxSpeed=" + maxSpeed); + if (Config.ENTITY_SPEED_A_KICKOUT) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().leaveVehicle()); + } + } + } + else { + this.decayBuffer(); + } + } + else if (ServerUtil.isHigherThan1_12() && this.data.getPlayer().getVehicle() instanceof Donkey) { + final Donkey donkey = (Donkey)this.data.getPlayer().getVehicle(); + if (donkey == null || donkey.isLeashed()) { + return; + } + double maxSpeed = donkey.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getBaseValue() * 2.25 + 0.1; + if (donkey.hasPotionEffect(PotionEffectType.SPEED)) { + maxSpeed += PlayerUtil.getSpeed(donkey) * 0.15; + } + if (this.data.getActionProcessor().isHasSpeed()) { + maxSpeed += this.data.getActionProcessor().getSpeedAmplifier() * 0.065; + } + if (!ground) { + maxSpeed += 0.17499999701976776; + } + if (deltaXZ > maxSpeed && !ice && vehicleTicks > 10) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("[Donkey] speed=" + deltaXZ + " maxSpeed=" + maxSpeed); + if (Config.ENTITY_SPEED_A_KICKOUT) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().leaveVehicle()); + } + } + } + else { + this.decayBuffer(); + } + } + else if (ServerUtil.isHigherThan1_12() && this.data.getPlayer().getVehicle() instanceof ZombieHorse) { + final ZombieHorse zombieHorse = (ZombieHorse)this.data.getPlayer().getVehicle(); + if (zombieHorse == null || zombieHorse.isLeashed()) { + return; + } + double maxSpeed = zombieHorse.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getBaseValue() * 2.25 + 0.1; + if (zombieHorse.hasPotionEffect(PotionEffectType.SPEED)) { + maxSpeed += PlayerUtil.getSpeed(zombieHorse) * 0.15; + } + if (this.data.getActionProcessor().isHasSpeed()) { + maxSpeed += this.data.getActionProcessor().getSpeedAmplifier() * 0.065; + } + if (!ground) { + maxSpeed += 0.17499999701976776; + } + if (deltaXZ > maxSpeed && !ice && vehicleTicks > 10) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("[Zombie Horse] speed=" + deltaXZ + " maxSpeed=" + maxSpeed); + if (Config.ENTITY_SPEED_A_KICKOUT) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().leaveVehicle()); + } + } + } + else { + this.decayBuffer(); + } + } + else if (ServerUtil.isHigherThan1_12() && this.data.getPlayer().getVehicle() instanceof SkeletonHorse) { + final SkeletonHorse skeletonHorse = (SkeletonHorse)this.data.getPlayer().getVehicle(); + if (skeletonHorse == null || skeletonHorse.isLeashed()) { + return; + } + double maxSpeed = skeletonHorse.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getBaseValue() * 2.25 + 0.1; + if (skeletonHorse.hasPotionEffect(PotionEffectType.SPEED)) { + maxSpeed += PlayerUtil.getSpeed(skeletonHorse) * 0.15; + } + if (this.data.getActionProcessor().isHasSpeed()) { + maxSpeed += this.data.getActionProcessor().getSpeedAmplifier() * 0.065; + } + if (!ground) { + maxSpeed += 0.17499999701976776; + } + if (deltaXZ > maxSpeed && !ice && vehicleTicks > 10) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("[Skeleton Horse] speed=" + deltaXZ + " maxSpeed=" + maxSpeed); + if (Config.ENTITY_SPEED_A_KICKOUT) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().leaveVehicle()); + } + } + } + else { + this.decayBuffer(); + } + } + else if (vehicleBoat) { + double max = 0.65; + if (liquid) { + max += 0.15; + } + if (deltaXZ > max && !ice && !bubbleColumn && !slime && vehicleTicks > 5) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("[Boat] deltaXZ=" + deltaXZ); + if (Config.ENTITY_SPEED_A_KICKOUT) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().leaveVehicle()); + } + } + } + else { + this.decayBuffer(); + } + } + else if (vehiclePig) { + final Pig pig = (Pig)this.data.getPlayer().getVehicle(); + if (pig == null || pig.isLeashed()) { + return; + } + final double maxSpeed = pig.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getBaseValue() * 2.25 + 0.1; + if (deltaXZ > maxSpeed && ground && !ice && vehicleTicks > 10) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("[Pig] speed=" + deltaXZ + " maxSpeed=" + maxSpeed); + if (Config.ENTITY_SPEED_A_KICKOUT) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().leaveVehicle()); + } + } + } + else { + this.decayBuffer(); + } + } + else if (ServerUtil.isHigherThan1_16() && this.data.getPlayer().getVehicle() instanceof Strider) { + final Strider strider = (Strider)this.data.getPlayer().getVehicle(); + if (strider == null || strider.isLeashed()) { + return; + } + double maxSpeed = strider.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getBaseValue() * 2.25 + 0.1; + if (strider.hasPotionEffect(PotionEffectType.SPEED)) { + maxSpeed += PlayerUtil.getSpeed(strider) * 0.15; + } + if (this.data.getActionProcessor().isHasSpeed()) { + maxSpeed += this.data.getActionProcessor().getSpeedAmplifier() * 0.065; + } + if (!ground) { + maxSpeed += 0.17499999701976776; + } + if (deltaXZ > maxSpeed && !ice && vehicleTicks > 10) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("[Strider] speed=" + deltaXZ + " maxSpeed=" + maxSpeed); + if (Config.ENTITY_SPEED_A_KICKOUT) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().leaveVehicle()); + } + } + } + else { + this.decayBuffer(); + } + } + else if (ServerUtil.isHigherThan1_11() && this.data.getPlayer().getVehicle() instanceof Llama) { + final Llama llama = (Llama)this.data.getPlayer().getVehicle(); + if (llama == null || llama.isLeashed()) { + return; + } + double maxSpeed = llama.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getBaseValue() * 2.25 + 0.1; + if (llama.hasPotionEffect(PotionEffectType.SPEED)) { + maxSpeed += PlayerUtil.getSpeed(llama) * 0.15; + } + if (this.data.getActionProcessor().isHasSpeed()) { + maxSpeed += this.data.getActionProcessor().getSpeedAmplifier() * 0.065; + } + if (!ground) { + maxSpeed += 0.17499999701976776; + } + if (deltaXZ > maxSpeed && !ice && vehicleTicks > 10) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("[Llama] speed=" + deltaXZ + " maxSpeed=" + maxSpeed); + if (Config.ENTITY_SPEED_A_KICKOUT) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().leaveVehicle()); + } + } + } + else { + this.decayBuffer(); + } + } + else if (ServerUtil.isHigherThan1_11() && this.data.getPlayer().getVehicle() instanceof TraderLlama) { + final TraderLlama traderLlama = (TraderLlama)this.data.getPlayer().getVehicle(); + if (traderLlama == null || traderLlama.isLeashed()) { + return; + } + double maxSpeed = traderLlama.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getBaseValue() * 2.25 + 0.1; + if (traderLlama.hasPotionEffect(PotionEffectType.SPEED)) { + maxSpeed += PlayerUtil.getSpeed(traderLlama) * 0.15; + } + if (this.data.getActionProcessor().isHasSpeed()) { + maxSpeed += this.data.getActionProcessor().getSpeedAmplifier() * 0.065; + } + if (!ground) { + maxSpeed += 0.17499999701976776; + } + if (deltaXZ > maxSpeed && !ice && vehicleTicks > 10) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("[TraderLlama] speed=" + deltaXZ + " maxSpeed=" + maxSpeed); + if (Config.ENTITY_SPEED_A_KICKOUT) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().leaveVehicle()); + } + } + } + else { + this.decayBuffer(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/fastclimb/FastClimbA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/fastclimb/FastClimbA.java new file mode 100644 index 0000000..abd2272 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/fastclimb/FastClimbA.java @@ -0,0 +1,60 @@ +package me.frep.vulcan.spigot.check.impl.movement.fastclimb; + +import org.bukkit.Material; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.BlockUtil; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Fast Climb", type = 'A', complexType = "Limit", description = "Climbing too quickly") +public class FastClimbA extends AbstractCheck +{ + public FastClimbA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition()) { + final int climbableTicks = this.data.getPositionProcessor().getClimbableTicks(); + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final boolean onClimbable = this.data.getPositionProcessor().isOnClimbable(); + if (this.data.getActionProcessor().getDistanceFromLastBreak() < 1.25 && this.data.getActionProcessor().getDistanceFromLastBreak() > 0.0) { + return; + } + boolean valid = false; + if (ServerUtil.isHigherThan1_13()) { + if (this.data.getPositionProcessor().getBlockBelowModern() != null && this.data.getPositionProcessor().getBlockBelow2Modern() != null) { + final Material below = this.data.getPositionProcessor().getBlockBelowModern(); + final Material below2 = this.data.getPositionProcessor().getBlockBelow2Modern(); + if (BlockUtil.isClimbable(below) && BlockUtil.isClimbable(below2)) { + valid = true; + } + } + } + else if (this.data.getPositionProcessor().getBlockBelow() != null && this.data.getPositionProcessor().getBlockBelow2() != null) { + final Material below = this.data.getPositionProcessor().getBlockBelow(); + final Material below2 = this.data.getPositionProcessor().getBlockBelow2(); + if (BlockUtil.isClimbable(below) && BlockUtil.isClimbable(below2)) { + valid = true; + } + } + if (!valid) { + return; + } + final boolean invalid = deltaY > 0.118 && climbableTicks > 3 && onClimbable; + final boolean exempt = this.isExempt(ExemptType.JUMP_BOOST, ExemptType.FLIGHT, ExemptType.CREATIVE, ExemptType.GLIDING, ExemptType.LEVITATION, ExemptType.SLEEPING, ExemptType.ENDER_PEARL, ExemptType.TELEPORT, ExemptType.WORLD_CHANGE, ExemptType.DEATH, ExemptType.SCAFFOLDING, ExemptType.LIQUID, ExemptType.WATERLOGGED, ExemptType.BLOCK_PLACE, ExemptType.RIPTIDE, ExemptType.LIQUID, ExemptType.BUBBLE_COLUMN, ExemptType.SLIME, ExemptType.PROJECTILE_DAMAGE, ExemptType.BUKKIT_VELOCITY, ExemptType.WALL); + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER || deltaY > 1.0) { + this.fail("deltaY=" + deltaY + " ticks=" + climbableTicks); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/flight/FlightA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/flight/FlightA.java new file mode 100644 index 0000000..6bf8d1f --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/flight/FlightA.java @@ -0,0 +1,57 @@ +package me.frep.vulcan.spigot.check.impl.movement.flight; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Flight", type = 'A', complexType = "Prediction [S]", description = "Invalid Y-Axis movement.") +public class FlightA extends AbstractCheck +{ + public FlightA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting() && !this.fuckedPosition()) { + if (Config.FLIGHT_A_IGNORE_GHOST_BLOCKS && this.data.getPositionProcessor().isClientOnGround() && this.data.getPositionProcessor().isTouchingAir() && this.data.getPositionProcessor().isMathematicallyOnGround()) { + return; + } + final int airTicks = this.data.getPositionProcessor().getServerAirTicks(); + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final boolean ladder = Math.abs(deltaY - 0.11760000228882461) <= 0.001; + if (ladder && this.isExempt(ExemptType.FAST)) { + return; + } + if (deltaY + 0.09800000190734881 <= 0.001) { + return; + } + final double lastDeltaY = this.data.getPositionProcessor().getLastDeltaY(); + final double prediction = (lastDeltaY - 0.08) * 0.9800000190734863; + final double difference = Math.abs(deltaY - prediction); + final boolean explosion = this.data.getActionProcessor().getSinceExplosionDamageTicks() < 40; + if (airTicks < 30 && this.isExempt(ExemptType.PISTON)) { + return; + } + final long delay = this.data.getConnectionProcessor().getFlyingDelay(); + int maxTicks = 6; + if (this.data.getActionProcessor().isHasJumpBoost()) { + maxTicks += this.data.getActionProcessor().getJumpBoostAmplifier(); + } + final boolean invalid = airTicks > maxTicks && difference > 1.0E-8 && airTicks > 6; + final boolean exempt = this.isExempt(ExemptType.SHULKER_BOX, ExemptType.WEB, ExemptType.BOAT, ExemptType.ILLEGAL_BLOCK, ExemptType.SLEEPING, ExemptType.SHULKER, ExemptType.TRAPDOOR, ExemptType.FISHING_ROD, ExemptType.SERVER_POSITION_FAST, ExemptType.LILY_PAD, ExemptType.SPECTATOR, ExemptType.HONEY, ExemptType.CHORUS_FRUIT, ExemptType.BED, ExemptType.CHAIN, ExemptType.WORLD_CHANGE, ExemptType.CANCELLED_PLACE, ExemptType.LAGGED_NEAR_GROUND_MODERN, ExemptType.EMPTIED_BUCKET, ExemptType.DEAD, ExemptType.CANCELLED_BREAK, ExemptType.FENCE, ExemptType.LAGGED_NEAR_GROUND, ExemptType.BLOCK_PLACE_FAST, ExemptType.GLASS_PANE, ExemptType.NOT_MOVING) || this.data.getPositionProcessor().isExemptFlight() || this.data.getPositionProcessor().isExemptCreative() || this.data.getPositionProcessor().isExemptJoined() || this.data.getPositionProcessor().isExemptLiquid() || this.data.getPositionProcessor().isExemptLevitation() || this.data.getPositionProcessor().isExemptSlowFalling() || this.data.getPositionProcessor().isExemptRiptide() || this.data.getPositionProcessor().isExemptVehicle() || this.data.getPositionProcessor().isExemptLenientScaffolding() || this.data.getPositionProcessor().isExemptBukkitVelocity() || this.data.getPositionProcessor().isExemptTeleport() || this.data.getPositionProcessor().isExemptEnderPearl() || this.data.getPositionProcessor().isExemptGliding() || this.data.getPositionProcessor().isExemptElytra() || this.data.getPositionProcessor().isExemptChunk() || this.data.getPositionProcessor().isExemptComboMode() || this.data.getPositionProcessor().isExemptMythicMob() || this.data.getPositionProcessor().isExemptClimbable(); + final int sinceTeleportTicks = this.data.getActionProcessor().getSinceTeleportTicks(); + if (invalid && !exempt && !explosion) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaY=" + deltaY + " difference=" + difference + " ticks=" + airTicks + " delay=" + delay + " tp=" + sinceTeleportTicks); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/flight/FlightB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/flight/FlightB.java new file mode 100644 index 0000000..d16bbd1 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/flight/FlightB.java @@ -0,0 +1,69 @@ +package me.frep.vulcan.spigot.check.impl.movement.flight; + +import java.util.Iterator; +import me.frep.vulcan.spigot.util.value.Values; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Flight", type = 'B', complexType = "Prediction [C]", description = "Invalid Y-Axis movement.") +public class FlightB extends AbstractCheck +{ + public FlightB(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting() && !this.fuckedPosition()) { + if (this.data.getActionProcessor().getJumpBoostAmplifier() > 50) { + return; + } + final int airTicks = this.data.getPositionProcessor().getClientAirTicks(); + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final double lastDeltaY = this.data.getPositionProcessor().getLastDeltaY(); + final boolean ladder = Math.abs(deltaY - 0.11760000228882461) <= 0.001; + if (ladder) { + return; + } + final double prediction = (lastDeltaY - 0.08) * 0.9800000190734863; + final double difference = Math.abs(deltaY - prediction); + if (deltaY + 0.09800000190734881 <= 0.005) { + return; + } + final boolean explosion = this.data.getActionProcessor().getSinceExplosionDamageTicks() < 40; + final boolean exempt = this.isExempt(ExemptType.BOAT, ExemptType.PARTIALLY_STUCK, ExemptType.DEAD, ExemptType.WEB, ExemptType.PLACING, ExemptType.WATERLOGGED, ExemptType.SLIME, ExemptType.WORLD_CHANGE, ExemptType.HONEY, ExemptType.FISHING_ROD, ExemptType.EMPTIED_BUCKET, ExemptType.SWEET_BERRIES, ExemptType.BUBBLE_COLUMN, ExemptType.SCAFFOLDING, ExemptType.NOT_MOVING, ExemptType.SEAGRASS, ExemptType.SIGN, ExemptType.ANVIL, ExemptType.END_ROD, ExemptType.SPECTATOR, ExemptType.SHULKER, ExemptType.SHULKER_BOX, ExemptType.FENCE, ExemptType.KELP, ExemptType.BLOCK_BREAK, ExemptType.FENCE_GATE, ExemptType.JOINED_CHUNK_LOAD, ExemptType.DOLPHINS_GRACE, ExemptType.PLACED_WEB, ExemptType.SEAGRASS, ExemptType.WALL, ExemptType.SEA_PICKLE, ExemptType.CHEST, ExemptType.DRIPSTONE, ExemptType.POWDER_SNOW, ExemptType.FULLY_STUCK, ExemptType.BED, ExemptType.SLEEPING, ExemptType.CANCELLED_MOVE, ExemptType.SIGN) || this.data.getPositionProcessor().isExemptFlight() || this.data.getPositionProcessor().isExemptCreative() || this.data.getPositionProcessor().isExemptJoined() || this.data.getPositionProcessor().isExemptLiquid() || this.data.getPositionProcessor().isExemptLevitation() || this.data.getPositionProcessor().isExemptSlowFalling() || this.data.getPositionProcessor().isExemptRiptide() || this.data.getPositionProcessor().isExemptVehicle() || this.data.getPositionProcessor().isExemptLenientScaffolding() || this.data.getPositionProcessor().isExemptBukkitVelocity() || this.data.getPositionProcessor().isExemptTeleport() || this.data.getPositionProcessor().isExemptEnderPearl() || this.data.getPositionProcessor().isExemptGliding() || this.data.getPositionProcessor().isExemptElytra() || this.data.getPositionProcessor().isExemptChunk() || this.data.getPositionProcessor().isExemptComboMode() || this.data.getPositionProcessor().isExemptMythicMob() || this.data.getPositionProcessor().isExemptClimbable(); + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final boolean nearGround = this.data.getPositionProcessor().isNearGround(); + if (Config.GHOST_WATER_FIX && deltaXZ < 0.15 && nearGround) { + for (final double value : Values.WATER_VALUES) { + if (Math.abs(deltaY) > 0.0 && Math.abs(deltaY - value) < 0.01) { + return; + } + } + } + final boolean velocity = this.data.getVelocityProcessor().getTransactionFlyingTicks() < 20 && airTicks < 20; + int maxTicks = 7; + if (this.data.getActionProcessor().isHasJumpBoost()) { + maxTicks += this.data.getActionProcessor().getJumpBoostAmplifier(); + } + if (this.data.getActionProcessor().getSinceAttackDamageTicks() < 15) { + maxTicks += 7; + } + final boolean invalid = airTicks > maxTicks && difference > 1.0E-8; + final int teleportTicks = this.data.getActionProcessor().getSinceTeleportTicks(); + final long delay = this.data.getConnectionProcessor().getFlyingDelay(); + if (invalid && !exempt && !velocity && !explosion) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaY=" + deltaY + " difference=" + difference + " ticks=" + airTicks + " delay=" + delay + " tp=" + teleportTicks); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/flight/FlightC.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/flight/FlightC.java new file mode 100644 index 0000000..d48736b --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/flight/FlightC.java @@ -0,0 +1,53 @@ +package me.frep.vulcan.spigot.check.impl.movement.flight; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Flight", type = 'C', complexType = "Ascension", description = "Invalid Y-Axis movement.") +public class FlightC extends AbstractCheck +{ + public FlightC(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting() && !this.fuckedPosition()) { + if (Config.FLIGHT_C_IGNORE_GHOST_BLOCKS && this.data.getPositionProcessor().isClientOnGround() && this.data.getPositionProcessor().isTouchingAir() && this.data.getPositionProcessor().isMathematicallyOnGround()) { + return; + } + if (this.data.getActionProcessor().getSinceDragonDamageTicks() < 200) { + return; + } + final int airTicks = this.data.getPositionProcessor().getServerAirTicks(); + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + int maxTicks = 7; + if (this.isExempt(ExemptType.BLOCK_PLACE, ExemptType.CANCELLED_PLACE)) { + maxTicks += 15; + } + if (Math.abs(deltaY) - 0.08307781780646728 < 0.001) { + return; + } + final boolean invalid = airTicks > maxTicks && deltaY > 0.0; + final boolean bed = this.data.getPositionProcessor().getSinceNearBedTicks() < 30; + final boolean explosion = this.data.getActionProcessor().getSinceExplosionDamageTicks() < 100; + final boolean slime = this.data.getPositionProcessor().getSinceNearSlimeTicks() < 80 || this.data.getActionProcessor().getSinceSlimePlaceTicks() < 80; + final boolean exempt = this.isExempt(ExemptType.SHULKER_BOX, ExemptType.BOAT, ExemptType.WORLD_CHANGE, ExemptType.JUMP_BOOST, ExemptType.FENCE, ExemptType.LAGGED_NEAR_GROUND, ExemptType.ILLEGAL_BLOCK, ExemptType.SHULKER, ExemptType.FROZEN, ExemptType.FISHING_ROD, ExemptType.CANCELLED_PLACE, ExemptType.NOT_MOVING, ExemptType.SPECTATOR, ExemptType.CHORUS_FRUIT, ExemptType.PISTON, ExemptType.NEAR_GROUND, ExemptType.LAGGED_NEAR_GROUND_MODERN, ExemptType.EMPTIED_BUCKET, ExemptType.BOAT, ExemptType.PLACED_SLIME, ExemptType.DEAD) || this.data.getPositionProcessor().isExemptFlight() || this.data.getPositionProcessor().isExemptCreative() || this.data.getPositionProcessor().isExemptJoined() || this.data.getPositionProcessor().isExemptLiquid() || this.data.getPositionProcessor().isExemptLevitation() || this.data.getPositionProcessor().isExemptSlowFalling() || this.data.getPositionProcessor().isExemptRiptide() || this.data.getPositionProcessor().isExemptVehicle() || this.data.getPositionProcessor().isExemptLenientScaffolding() || this.data.getPositionProcessor().isExemptBukkitVelocity() || this.data.getPositionProcessor().isExemptTeleport() || this.data.getPositionProcessor().isExemptEnderPearl() || this.data.getPositionProcessor().isExemptGliding() || this.data.getPositionProcessor().isExemptElytra() || this.data.getPositionProcessor().isExemptChunk() || this.data.getPositionProcessor().isExemptComboMode() || this.data.getPositionProcessor().isExemptMythicMob() || this.data.getPositionProcessor().isExemptClimbable(); + final long delay = this.data.getConnectionProcessor().getFlyingDelay(); + final boolean velocity = this.data.getActionProcessor().getSinceNonFallDamageTicks() < 40 && airTicks < 30; + final int sinceTeleportTicks = this.data.getActionProcessor().getSinceTeleportTicks(); + if (invalid && !exempt && !slime && !velocity && !bed && !explosion) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaY=" + deltaY + " ticks=" + airTicks + " delay=" + delay + " tp=" + sinceTeleportTicks); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/flight/FlightD.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/flight/FlightD.java new file mode 100644 index 0000000..8c5ae81 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/flight/FlightD.java @@ -0,0 +1,52 @@ +package me.frep.vulcan.spigot.check.impl.movement.flight; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Flight", type = 'D', complexType = "Glide", description = "Invalid Y-Axis movement.") +public class FlightD extends AbstractCheck +{ + public FlightD(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting() && !this.fuckedPosition()) { + if (Config.FLIGHT_D_IGNORE_GHOST_BLOCKS && this.data.getPositionProcessor().isClientOnGround() && this.data.getPositionProcessor().isTouchingAir() && this.data.getPositionProcessor().isMathematicallyOnGround()) { + return; + } + final int airTicks = this.data.getPositionProcessor().getServerAirTicks(); + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + if (this.data.getActionProcessor().getSinceDragonDamageTicks() < 200) { + return; + } + if (deltaY + 0.09800000190734881 <= 0.001) { + return; + } + final boolean explosion = this.data.getActionProcessor().getSinceExplosionDamageTicks() < 100; + final boolean velocity = this.data.getActionProcessor().getSinceNonFallDamageTicks() < 40 && airTicks < 30; + final boolean bed = this.data.getPositionProcessor().getSinceNearBedTicks() < 30; + final boolean exempt = this.isExempt(ExemptType.LAGGED_NEAR_GROUND, ExemptType.DEAD, ExemptType.WEB, ExemptType.JUMP_BOOST_RAN_OUT, ExemptType.EMPTIED_BUCKET, ExemptType.WORLD_CHANGE, ExemptType.ILLEGAL_BLOCK, ExemptType.BOAT, ExemptType.LIQUID, ExemptType.NOT_MOVING, ExemptType.FENCE, ExemptType.SHULKER, ExemptType.TRAPDOOR, ExemptType.SHULKER_BOX, ExemptType.NEAR_GROUND, ExemptType.FISHING_ROD, ExemptType.LAGGED_NEAR_GROUND_MODERN, ExemptType.VOID, ExemptType.CANCELLED_PLACE, ExemptType.SPECTATOR, ExemptType.SERVER_POSITION, ExemptType.PISTON, ExemptType.HIGH_JUMP_BOOST, ExemptType.NEAR_GROUND, ExemptType.SLIME, ExemptType.PARTIALLY_STUCK, ExemptType.FULLY_STUCK, ExemptType.RESPAWN, ExemptType.PLACED_SLIME) || this.data.getPositionProcessor().isExemptFlight() || this.data.getPositionProcessor().isExemptCreative() || this.data.getPositionProcessor().isExemptJoined() || this.data.getPositionProcessor().isExemptLiquid() || this.data.getPositionProcessor().isExemptLevitation() || this.data.getPositionProcessor().isExemptSlowFalling() || this.data.getPositionProcessor().isExemptRiptide() || this.data.getPositionProcessor().isExemptVehicle() || this.data.getPositionProcessor().isExemptLenientScaffolding() || this.data.getPositionProcessor().isExemptBukkitVelocity() || this.data.getPositionProcessor().isExemptTeleport() || this.data.getPositionProcessor().isExemptEnderPearl() || this.data.getPositionProcessor().isExemptGliding() || this.data.getPositionProcessor().isExemptElytra() || this.data.getPositionProcessor().isExemptChunk() || this.data.getPositionProcessor().isExemptComboMode() || this.data.getPositionProcessor().isExemptMythicMob() || this.data.getPositionProcessor().isExemptClimbable(); + int maxTicks = 18; + if (this.isExempt(ExemptType.BLOCK_PLACE, ExemptType.CANCELLED_PLACE)) { + maxTicks += 30; + } + final long delay = this.data.getConnectionProcessor().getFlyingDelay(); + final boolean invalid = airTicks > maxTicks && deltaY > -0.5; + final int sinceTeleportTicks = this.data.getActionProcessor().getSinceTeleportTicks(); + if (invalid && !exempt && !velocity && !explosion && !bed) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaY=" + deltaY + " ticks=" + airTicks + " delay=" + delay + " tp=" + sinceTeleportTicks); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/flight/FlightE.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/flight/FlightE.java new file mode 100644 index 0000000..4611798 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/flight/FlightE.java @@ -0,0 +1,42 @@ +package me.frep.vulcan.spigot.check.impl.movement.flight; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Flight", type = 'E', complexType = "Hover", description = "Invalid Y-Axis movement.") +public class FlightE extends AbstractCheck +{ + public FlightE(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting() && !this.fuckedPosition()) { + if (Config.FLIGHT_E_IGNORE_GHOST_BLOCKS && this.data.getPositionProcessor().isClientOnGround() && this.data.getPositionProcessor().isTouchingAir() && this.data.getPositionProcessor().isMathematicallyOnGround()) { + return; + } + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final double lastDeltaY = this.data.getPositionProcessor().getLastDeltaY(); + final double acceleration = Math.abs(deltaY - lastDeltaY); + final boolean touchingAir = this.data.getPositionProcessor().isTouchingAir(); + final int airTicks = this.data.getPositionProcessor().getServerAirTicks(); + final long delay = this.data.getConnectionProcessor().getFlyingDelay(); + final boolean invalid = airTicks > 3 && Math.abs(deltaY) < 0.5 && acceleration < 0.05 && touchingAir; + final boolean exempt = this.isExempt(ExemptType.BED, ExemptType.EMPTIED_BUCKET, ExemptType.WEB, ExemptType.LAGGED_NEAR_GROUND, ExemptType.SLEEPING, ExemptType.JOINED_CHUNK_LOAD, ExemptType.ILLEGAL_BLOCK, ExemptType.BOAT, ExemptType.SHULKER, ExemptType.BLOCK_PLACE, ExemptType.LAGGED_NEAR_GROUND_MODERN, ExemptType.TRAPDOOR, ExemptType.WORLD_CHANGE, ExemptType.NOT_MOVING, ExemptType.LILY_PAD, ExemptType.SPECTATOR, ExemptType.SHULKER_BOX, ExemptType.HONEY, ExemptType.CANCELLED_PLACE, ExemptType.FENCE, ExemptType.SWEET_BERRIES, ExemptType.DEAD) || this.data.getPositionProcessor().isExemptFlight() || this.data.getPositionProcessor().isExemptCreative() || this.data.getPositionProcessor().isExemptJoined() || this.data.getPositionProcessor().isExemptLiquid() || this.data.getPositionProcessor().isExemptLevitation() || this.data.getPositionProcessor().isExemptSlowFalling() || this.data.getPositionProcessor().isExemptRiptide() || this.data.getPositionProcessor().isExemptVehicle() || this.data.getPositionProcessor().isExemptLenientScaffolding() || this.data.getPositionProcessor().isExemptBukkitVelocity() || this.data.getPositionProcessor().isExemptTeleport() || this.data.getPositionProcessor().isExemptEnderPearl() || this.data.getPositionProcessor().isExemptGliding() || this.data.getPositionProcessor().isExemptElytra() || this.data.getPositionProcessor().isExemptChunk() || this.data.getPositionProcessor().isExemptComboMode() || this.data.getPositionProcessor().isExemptMythicMob() || this.data.getPositionProcessor().isExemptClimbable(); + final int sinceTeleportTicks = this.data.getActionProcessor().getSinceTeleportTicks(); + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " acceleration=" + acceleration + " deltaY=" + deltaY + " delay=" + delay + " tp=" + sinceTeleportTicks); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/jesus/JesusA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/jesus/JesusA.java new file mode 100644 index 0000000..c33f83d --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/jesus/JesusA.java @@ -0,0 +1,35 @@ +package me.frep.vulcan.spigot.check.impl.movement.jesus; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Jesus", type = 'A', complexType = "Ground", description = "Walking on water.") +public class JesusA extends AbstractCheck +{ + public JesusA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition()) { + final boolean onLiquid = this.data.getPositionProcessor().isOnLiquid(); + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final boolean clientOnGround = this.data.getPositionProcessor().isClientOnGround(); + final boolean serverOnGround = this.data.getPositionProcessor().isMathematicallyOnGround(); + final boolean exempt = this.isExempt(ExemptType.LILY_PAD, ExemptType.STAIRS, ExemptType.SLAB, ExemptType.CAMPFIRE, ExemptType.CARPET, ExemptType.END_ROD, ExemptType.FENCE, ExemptType.BOAT, ExemptType.CANCELLED_PLACE, ExemptType.CHAIN, ExemptType.SNOW, ExemptType.SWIMMING_JESUS, ExemptType.BED, ExemptType.TRAPDOOR, ExemptType.BOAT, ExemptType.DEPTH_STRIDER, ExemptType.DOLPHINS_GRACE, ExemptType.SPECTATOR, ExemptType.SCAFFOLDING, ExemptType.NEAR_SOLID, ExemptType.NOT_MOVING, ExemptType.BLOCK_PLACE) || this.data.getPositionProcessor().isExemptFlight() || this.data.getPositionProcessor().isExemptGliding() || this.data.getPositionProcessor().isExemptElytra() || this.data.getPositionProcessor().isExemptLevitation() || this.data.getPositionProcessor().isExemptVehicle() || this.data.getPositionProcessor().isExemptRiptide() || this.data.getPositionProcessor().isExemptTeleport() || this.data.getPositionProcessor().isExemptChunk(); + if (onLiquid && (clientOnGround || serverOnGround) && !exempt && deltaXZ > 0.1) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail(); + this.data.getActionProcessor().setUpdateSwim(true); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/jesus/JesusB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/jesus/JesusB.java new file mode 100644 index 0000000..255412a --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/jesus/JesusB.java @@ -0,0 +1,36 @@ +package me.frep.vulcan.spigot.check.impl.movement.jesus; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Jesus", type = 'B', complexType = "Motion", description = "Invalid Y-change in water.") +public class JesusB extends AbstractCheck +{ + public JesusB(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition()) { + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final boolean onLiquid = this.data.getPositionProcessor().isOnLiquid(); + final boolean exempt = this.isExempt(ExemptType.LILY_PAD, ExemptType.STAIRS, ExemptType.SLAB, ExemptType.CAMPFIRE, ExemptType.CARPET, ExemptType.END_ROD, ExemptType.FENCE, ExemptType.BOAT, ExemptType.CANCELLED_PLACE, ExemptType.CHAIN, ExemptType.SNOW, ExemptType.SWIMMING_JESUS, ExemptType.BED, ExemptType.TRAPDOOR, ExemptType.BOAT, ExemptType.FULLY_SUBMERGED, ExemptType.BUBBLE_COLUMN, ExemptType.VELOCITY, ExemptType.DEPTH_STRIDER, ExemptType.DOLPHINS_GRACE, ExemptType.SWIMMING_ON_OLD_VERSION, ExemptType.SPECTATOR, ExemptType.SOUL_SAND, ExemptType.NOT_MOVING, ExemptType.NEAR_SOLID, ExemptType.CHUNK, ExemptType.SCAFFOLDING, ExemptType.SLOW_FALLING) || this.data.getPositionProcessor().isExemptFlight() || this.data.getPositionProcessor().isExemptGliding() || this.data.getPositionProcessor().isExemptElytra() || this.data.getPositionProcessor().isExemptLevitation() || this.data.getPositionProcessor().isExemptVehicle() || this.data.getPositionProcessor().isExemptRiptide() || this.data.getPositionProcessor().isExemptTeleport(); + if (onLiquid && !exempt) { + if (Math.abs(deltaY) < 0.015 && deltaXZ > 0.11) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaY=" + deltaY + " deltaXZ=" + deltaXZ); + this.data.getActionProcessor().setUpdateSwim(true); + } + } + else { + this.decayBuffer(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/jesus/JesusC.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/jesus/JesusC.java new file mode 100644 index 0000000..ba6e79e --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/jesus/JesusC.java @@ -0,0 +1,33 @@ +package me.frep.vulcan.spigot.check.impl.movement.jesus; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Jesus", type = 'C', complexType = "Y Motion", description = "Invalid Y-Change in water.") +public class JesusC extends AbstractCheck +{ + public JesusC(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition()) { + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final boolean onLiquid = this.data.getPositionProcessor().isOnLiquid(); + final boolean exempt = this.isExempt(ExemptType.LILY_PAD, ExemptType.STAIRS, ExemptType.SLAB, ExemptType.CAMPFIRE, ExemptType.CARPET, ExemptType.END_ROD, ExemptType.FENCE, ExemptType.BOAT, ExemptType.CANCELLED_PLACE, ExemptType.CHAIN, ExemptType.SNOW, ExemptType.SWIMMING_JESUS, ExemptType.BED, ExemptType.TRAPDOOR, ExemptType.BOAT, ExemptType.FULLY_SUBMERGED, ExemptType.VELOCITY, ExemptType.BUBBLE_COLUMN, ExemptType.SWIMMING_ON_OLD_VERSION, ExemptType.SOUL_SAND, ExemptType.SPECTATOR, ExemptType.NEAR_SOLID, ExemptType.CHUNK, ExemptType.NOT_MOVING, ExemptType.SCAFFOLDING) || this.data.getPositionProcessor().isExemptFlight() || this.data.getPositionProcessor().isExemptGliding() || this.data.getPositionProcessor().isExemptElytra() || this.data.getPositionProcessor().isExemptLevitation() || this.data.getPositionProcessor().isExemptVehicle() || this.data.getPositionProcessor().isExemptRiptide() || this.data.getPositionProcessor().isExemptTeleport(); + if (onLiquid && !exempt && Math.abs(deltaY) < 0.001) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaY=" + deltaY); + this.data.getActionProcessor().setUpdateSwim(true); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/jesus/JesusD.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/jesus/JesusD.java new file mode 100644 index 0000000..42416aa --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/jesus/JesusD.java @@ -0,0 +1,42 @@ +package me.frep.vulcan.spigot.check.impl.movement.jesus; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.BlockUtil; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Jesus", type = 'D', complexType = "Jump", description = "Jumping on/in water.") +public class JesusD extends AbstractCheck +{ + public JesusD(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition()) { + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final boolean onLiquid = this.data.getPositionProcessor().isOnLiquid(); + boolean airBelow; + if (ServerUtil.isHigherThan1_13()) { + airBelow = (this.data.getPositionProcessor().getBlockBelowModern() != null && BlockUtil.isAir(this.data.getPositionProcessor().getBlockBelowModern())); + } + else { + airBelow = (this.data.getPositionProcessor().getBlockBelow() != null && BlockUtil.isAir(this.data.getPositionProcessor().getBlockBelow())); + } + final boolean exempt = this.isExempt(ExemptType.LILY_PAD, ExemptType.STAIRS, ExemptType.SLAB, ExemptType.CAMPFIRE, ExemptType.CARPET, ExemptType.END_ROD, ExemptType.FENCE, ExemptType.BOAT, ExemptType.NOT_MOVING, ExemptType.CANCELLED_PLACE, ExemptType.CHAIN, ExemptType.SNOW, ExemptType.SWIMMING_JESUS, ExemptType.BED, ExemptType.TRAPDOOR, ExemptType.BOAT, ExemptType.FULLY_SUBMERGED, ExemptType.VELOCITY, ExemptType.BUBBLE_COLUMN, ExemptType.SWIMMING_ON_OLD_VERSION, ExemptType.SPECTATOR, ExemptType.NEAR_SOLID, ExemptType.SLIME, ExemptType.HONEY, ExemptType.CHUNK, ExemptType.SCAFFOLDING) || this.data.getPositionProcessor().isExemptFlight() || this.data.getPositionProcessor().isExemptGliding() || this.data.getPositionProcessor().isExemptElytra() || this.data.getPositionProcessor().isExemptLevitation() || this.data.getPositionProcessor().isExemptVehicle() || this.data.getPositionProcessor().isExemptRiptide() || this.data.getPositionProcessor().isExemptTeleport(); + if (onLiquid && airBelow && !exempt) { + if (deltaY > 0.0 && this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaY=" + deltaY); + this.data.getActionProcessor().setUpdateSwim(true); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/jesus/JesusE.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/jesus/JesusE.java new file mode 100644 index 0000000..d76ab0b --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/jesus/JesusE.java @@ -0,0 +1,39 @@ +package me.frep.vulcan.spigot.check.impl.movement.jesus; + +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Jesus", type = 'E', complexType = "Speed", description = "Moving too quickly on water.") +public class JesusE extends AbstractCheck +{ + public JesusE(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition()) { + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final boolean onLiquid = this.data.getPositionProcessor().isOnLiquid(); + final boolean exempt = this.isExempt(ExemptType.LILY_PAD, ExemptType.STAIRS, ExemptType.SLAB, ExemptType.CAMPFIRE, ExemptType.CARPET, ExemptType.END_ROD, ExemptType.FENCE, ExemptType.NOT_MOVING, ExemptType.CANCELLED_PLACE, ExemptType.CHAIN, ExemptType.SNOW, ExemptType.SWIMMING_JESUS, ExemptType.BED, ExemptType.TRAPDOOR, ExemptType.BOAT, ExemptType.FULLY_SUBMERGED, ExemptType.BUBBLE_COLUMN, ExemptType.VELOCITY, ExemptType.DEPTH_STRIDER, ExemptType.DOLPHINS_GRACE, ExemptType.SWIMMING_ON_OLD_VERSION, ExemptType.SPECTATOR, ExemptType.BLOCK_PLACE, ExemptType.NEAR_SOLID, ExemptType.SLOW_FALLING, ExemptType.CHUNK, ExemptType.SCAFFOLDING, ExemptType.SLIME) || this.data.getPositionProcessor().isExemptFlight() || this.data.getPositionProcessor().isExemptGliding() || this.data.getPositionProcessor().isExemptElytra() || this.data.getPositionProcessor().isExemptLevitation() || this.data.getPositionProcessor().isExemptVehicle() || this.data.getPositionProcessor().isExemptRiptide() || this.data.getPositionProcessor().isExemptTeleport(); + double maxSpeed = PlayerUtil.getBaseSpeed(this.data, 0.166f); + if (ServerUtil.isHigherThan1_9() && this.data.getPositionProcessor().getSinceEntityCollisionTicks() < 20) { + maxSpeed += 0.2; + } + if (onLiquid && !exempt) { + if (deltaXZ > maxSpeed && this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaXZ=" + deltaXZ); + this.data.getActionProcessor().setUpdateSwim(true); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/jump/JumpA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/jump/JumpA.java new file mode 100644 index 0000000..d58871f --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/jump/JumpA.java @@ -0,0 +1,64 @@ +package me.frep.vulcan.spigot.check.impl.movement.jump; + +import java.util.Iterator; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.util.value.Values; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Jump", type = 'A', complexType = "Motion", description = "Invalid jump motion.") +public class JumpA extends AbstractCheck +{ + public JumpA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting()) { + if (this.data.getActionProcessor().isCrawling() || this.data.getPositionProcessor().getSinceNearBedTicks() < 30) { + return; + } + final int airTicks = this.data.getPositionProcessor().getClientAirTicks(); + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + if ((airTicks == 6 && deltaY < 0.033) || (airTicks == 7 && deltaY < 0.033)) { + return; + } + if (airTicks < 9 && airTicks > 0) { + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final boolean nearGround = this.data.getPositionProcessor().isNearGround(); + if (Config.GHOST_WATER_FIX && deltaXZ < 0.15 && nearGround) { + for (final double value : Values.WATER_VALUES) { + if (Math.abs(deltaY) > 0.0 && Math.abs(deltaY - value) < 0.01) { + return; + } + } + } + final double expected = Values.JUMP_MOTION.get(airTicks) + this.data.getActionProcessor().getJumpBoostAmplifier() * 0.1f; + final double difference = Math.abs(deltaY - expected); + if (System.currentTimeMillis() - this.data.getJoinTime() < 30000L) { + final double distance = MathUtil.magnitude(this.data.getPositionProcessor().getX() - this.data.getPositionProcessor().getFirstJoinX(), this.data.getPositionProcessor().getY() - this.data.getPositionProcessor().getFirstJoinY(), this.data.getPositionProcessor().getZ() - this.data.getPositionProcessor().getFirstJoinZ()); + if (distance < 4.0) { + return; + } + } + final boolean explosion = this.data.getActionProcessor().getSinceExplosionDamageTicks() < 80; + final boolean damage = this.data.getActionProcessor().getSinceDamageTicks() < 20; + final boolean exempt = this.isExempt(ExemptType.VELOCITY, ExemptType.COLLIDING_VERTICALLY, ExemptType.HOPPER, ExemptType.SLIME, ExemptType.SCAFFOLDING, ExemptType.BOAT, ExemptType.TRAPDOOR, ExemptType.STAIRS, ExemptType.SHULKER, ExemptType.FLIGHT, ExemptType.CREATIVE, ExemptType.SLAB, ExemptType.ILLEGAL_BLOCK, ExemptType.FENCE, ExemptType.JUMP_BOOST, ExemptType.HONEY, ExemptType.FISHING_ROD, ExemptType.WEB, ExemptType.FULLY_STUCK, ExemptType.SHULKER_BOX, ExemptType.VEHICLE, ExemptType.BED, ExemptType.BLOCK_PLACE, ExemptType.SEA_PICKLE, ExemptType.SLEEPING, ExemptType.CANCELLED_BREAK, ExemptType.ANVIL, ExemptType.PISTON, ExemptType.TURTLE_EGG, ExemptType.DOOR, ExemptType.DEATH, ExemptType.PARTIALLY_STUCK, ExemptType.WALL, ExemptType.PLACED_WEB, ExemptType.BUKKIT_VELOCITY, ExemptType.BUBBLE_COLUMN, ExemptType.FROZEN, ExemptType.KELP, ExemptType.BLOCK_BREAK, ExemptType.SWEET_BERRIES, ExemptType.EMPTIED_BUCKET, ExemptType.SERVER_POSITION_FAST, ExemptType.FARMLAND, ExemptType.LENIENT_SCAFFOLDING, ExemptType.ATTACK_DAMAGE, ExemptType.SEAGRASS, ExemptType.DRIPSTONE, ExemptType.WATERLOGGED, ExemptType.CHEST, ExemptType.SOUL_SAND, ExemptType.GLITCHED_BLOCKS_ABOVE, ExemptType.POWDER_SNOW, ExemptType.SIGN, ExemptType.SEA_PICKLE) || this.data.getPositionProcessor().isExemptJoined() || this.data.getPositionProcessor().isExemptTeleport() || this.data.getPositionProcessor().isExemptLiquid() || this.data.getPositionProcessor().isExemptClimbable() || this.data.getPositionProcessor().isExemptGliding() || this.data.getPositionProcessor().isExemptRiptide() || this.data.getPositionProcessor().isExemptElytra() || this.data.getPositionProcessor().isExemptEnderPearl() || this.data.getPositionProcessor().isExemptLevitation(); + final boolean invalid = deltaY > 0.0 && difference > 1.0E-10; + if (invalid && !exempt && !explosion && !damage) { + if (this.increaseBuffer() > this.MAX_BUFFER || (difference > 0.5 && difference < 10.0)) { + this.fail("deltaY=" + deltaY + " ticks=" + airTicks + " difference=" + difference); + } + } + else { + this.decayBuffer(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/jump/JumpB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/jump/JumpB.java new file mode 100644 index 0000000..b2b4fd2 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/jump/JumpB.java @@ -0,0 +1,70 @@ +package me.frep.vulcan.spigot.check.impl.movement.jump; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Jump", type = 'B', complexType = "Height", description = "Invalid jump motion.") +public class JumpB extends AbstractCheck +{ + public JumpB(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting()) { + if (this.data.getActionProcessor().getTicksExisted() < 30) { + return; + } + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final int airTicks = this.data.getPositionProcessor().getClientAirTicks(); + final boolean damage = this.data.getActionProcessor().getSinceNonFallDamageTicks() < 20; + final boolean bed = PlayerUtil.isHigherThan1_9(this.data.getPlayer()) && this.data.getPositionProcessor().getSinceNearBedTicks() < 40; + final boolean explosion = this.data.getActionProcessor().getSinceExplosionDamageTicks() < 100; + final boolean golem = this.data.getActionProcessor().getSinceIronGolemDamageTicks() < 30; + final boolean dragon = this.data.getActionProcessor().getSinceDragonDamageTicks() < 200; + final boolean fireball = this.isExempt(ExemptType.FIREBALL); + final boolean exempt = this.isExempt(ExemptType.JOINED, ExemptType.TELEPORT, ExemptType.RIPTIDE, ExemptType.VEHICLE, ExemptType.HONEY, ExemptType.GLIDING, ExemptType.LEVITATION, ExemptType.SLAB, ExemptType.STAIRS, ExemptType.FLIGHT, ExemptType.JUMP_BOOST_RAN_OUT, ExemptType.ELYTRA, ExemptType.BOAT, ExemptType.BUBBLE_COLUMN, ExemptType.WALL, ExemptType.CREATIVE, ExemptType.SHULKER_BOX, ExemptType.ANVIL, ExemptType.SLIME, ExemptType.PISTON, ExemptType.TURTLE_EGG, ExemptType.DOOR, ExemptType.DEATH, ExemptType.ENDER_PEARL, ExemptType.PLACED_SLIME, ExemptType.BUKKIT_VELOCITY, ExemptType.CHORUS_FRUIT, ExemptType.MYTHIC_MOB, ExemptType.BLOCK_BREAK, ExemptType.FISHING_ROD, ExemptType.SLEEPING, ExemptType.SHULKER); + double limit = 0.41999998688697815; + if (golem) { + limit += 0.4000000059604645; + } + if (fireball) { + limit += 0.5; + } + if (this.data.getPositionProcessor().isNearBed()) { + limit += 0.1; + } + if (this.isExempt(ExemptType.SKULL)) { + limit += 0.1; + } + if (this.data.getPositionProcessor().isNearPowderSnow()) { + limit += 0.5; + } + if (this.data.getActionProcessor().getSinceHoglinDamageTicks() < 20) { + limit += 0.15000000596046448; + } + if (this.data.getActionProcessor().isHasJumpBoost() && this.data.getActionProcessor().getJumpBoostAmplifier() > 0) { + limit += this.data.getActionProcessor().getJumpBoostAmplifier() * 0.125f; + } + if (this.data.getPositionProcessor().getSinceNearFenceTicks() < 5) { + limit += 0.125; + } + if (limit < 0.4) { + limit = 0.41999998688697815; + } + if (airTicks > 0 && deltaY > limit && !damage && !exempt && !bed && !explosion && !dragon) { + if (this.increaseBuffer() > this.MAX_BUFFER || (deltaY > 0.8 && deltaY < 15.0)) { + this.fail("deltaY=" + deltaY + " limit=" + limit + " tp=" + this.data.getActionProcessor().getSinceTeleportTicks()); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/motion/MotionA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/motion/MotionA.java new file mode 100644 index 0000000..ac499bb --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/motion/MotionA.java @@ -0,0 +1,38 @@ +package me.frep.vulcan.spigot.check.impl.movement.motion; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Motion", type = 'A', complexType = "Constant", description = "Repeated vertical motions.") +public class MotionA extends AbstractCheck +{ + public MotionA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting() && !this.fuckedPosition()) { + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final double lastDeltaY = this.data.getPositionProcessor().getLastDeltaY(); + final boolean ladder = Math.abs(deltaY - 0.11760000228882461) <= 0.001; + if (ladder) { + return; + } + final boolean climbable = this.data.getPositionProcessor().getSinceNearClimbableTicks() < 20; + final boolean exempt = this.isExempt(ExemptType.HALF_BLOCK, ExemptType.CLIMBABLE, ExemptType.FLIGHT, ExemptType.BED, ExemptType.LIQUID, ExemptType.TELEPORT, ExemptType.VELOCITY, ExemptType.ILLEGAL_BLOCK, ExemptType.SLEEPING, ExemptType.SOUL_SAND, ExemptType.HONEY, ExemptType.SLIME, ExemptType.LEVITATION, ExemptType.SPECTATOR, ExemptType.SCAFFOLDING, ExemptType.FENCE, ExemptType.BUBBLE_COLUMN, ExemptType.CREATIVE, ExemptType.SHULKER, ExemptType.SHULKER_BOX, ExemptType.ELYTRA, ExemptType.GLIDING, ExemptType.CANCELLED_PLACE, ExemptType.LENIENT_SCAFFOLDING, ExemptType.PLACED_CLIMBABLE, ExemptType.KELP, ExemptType.BOAT, ExemptType.CHUNK, ExemptType.TRAPDOOR, ExemptType.POWDER_SNOW, ExemptType.EMPTIED_BUCKET); + final boolean invalid = deltaY > 0.0 && deltaY == lastDeltaY; + if (invalid && !exempt && !climbable) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaY=" + deltaY); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/motion/MotionB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/motion/MotionB.java new file mode 100644 index 0000000..ce69bc1 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/motion/MotionB.java @@ -0,0 +1,35 @@ +package me.frep.vulcan.spigot.check.impl.movement.motion; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Motion", type = 'B', complexType = "Inverse", description = "Repeated vertical motions.") +public class MotionB extends AbstractCheck +{ + public MotionB(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting()) { + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final double lastDeltaY = this.data.getPositionProcessor().getLastDeltaY(); + final boolean chorus = this.data.getActionProcessor().getSinceChorusFruitTeleportTicks() < 50; + final boolean lectern = this.data.getPositionProcessor().isNearLectern() || this.data.getPositionProcessor().isNearRepeater(); + final boolean exempt = this.isExempt(ExemptType.WEB, ExemptType.LILY_PAD, ExemptType.JOINED, ExemptType.ELYTRA, ExemptType.ANVIL, ExemptType.SHULKER, ExemptType.SHULKER_BOX, ExemptType.PLACED_WEB, ExemptType.TELEPORT, ExemptType.RIPTIDE, ExemptType.CREATIVE, ExemptType.SPECTATOR, ExemptType.BUKKIT_VELOCITY, ExemptType.BOAT, ExemptType.WORLD_CHANGE, ExemptType.GLIDING, ExemptType.ENDER_PEARL, ExemptType.LIQUID, ExemptType.CHORUS_FRUIT, ExemptType.TRAPDOOR, ExemptType.CHUNK, ExemptType.PISTON, ExemptType.ILLEGAL_BLOCK, ExemptType.VELOCITY, ExemptType.LENIENT_SCAFFOLDING, ExemptType.CHORUS_FRUIT, ExemptType.FARMLAND, ExemptType.COLLIDING_VERTICALLY, ExemptType.TRAPDOOR, ExemptType.STAIRS, ExemptType.SLAB); + final boolean invalid = deltaY > 0.0 && deltaY == -lastDeltaY; + if (invalid && !exempt && !chorus && !lectern) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaY=" + deltaY); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/motion/MotionC.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/motion/MotionC.java new file mode 100644 index 0000000..004f49a --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/motion/MotionC.java @@ -0,0 +1,33 @@ +package me.frep.vulcan.spigot.check.impl.movement.motion; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Motion", type = 'C', complexType = "Jump", description = "Invalid jump motion.") +public class MotionC extends AbstractCheck +{ + public MotionC(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition()) { + final double deltaY = Math.abs(this.data.getPositionProcessor().getDeltaY()); + final double difference = Math.abs(deltaY - 0.41999998688697815); + final boolean exempt = this.isExempt(ExemptType.JUMP_BOOST, ExemptType.VELOCITY, ExemptType.FLIGHT, ExemptType.CREATIVE, ExemptType.SLIME, ExemptType.GLIDING, ExemptType.WEB, ExemptType.VEHICLE, ExemptType.SCAFFOLDING, ExemptType.LIQUID, ExemptType.SLAB, ExemptType.STAIRS, ExemptType.ELYTRA); + final boolean invalid = difference < 1.0E-5 && difference > 0.0 && deltaY > 0.1; + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaY=" + deltaY); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/motion/MotionD.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/motion/MotionD.java new file mode 100644 index 0000000..cf76c76 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/motion/MotionD.java @@ -0,0 +1,32 @@ +package me.frep.vulcan.spigot.check.impl.movement.motion; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Motion", type = 'D', complexType = "Exponent", description = "Too small Y-axis change.") +public class MotionD extends AbstractCheck +{ + public MotionD(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting()) { + final double deltaY = Math.abs(this.data.getPositionProcessor().getDeltaY()); + final boolean exempt = this.isExempt(ExemptType.LIQUID, ExemptType.GLIDING, ExemptType.RIPTIDE, ExemptType.BOAT, ExemptType.TELEPORT, ExemptType.SWIMMING, ExemptType.WEB, ExemptType.VELOCITY, ExemptType.PLACED_WEB, ExemptType.ELYTRA, ExemptType.FARMLAND, ExemptType.ENDER_PEARL, ExemptType.SLIME, ExemptType.PISTON, ExemptType.SHULKER, ExemptType.SHULKER_BOX, ExemptType.SLOW_FALLING, ExemptType.VEHICLE) || this.data.getPositionProcessor().isNearRail(); + final boolean invalid = deltaY < 0.003 && deltaY > 0.0; + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaY=" + deltaY); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/motion/MotionE.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/motion/MotionE.java new file mode 100644 index 0000000..5a388f8 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/motion/MotionE.java @@ -0,0 +1,36 @@ +package me.frep.vulcan.spigot.check.impl.movement.motion; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Motion", type = 'E', complexType = "Modulo", experimental = false, description = "Impossible movement values.") +public class MotionE extends AbstractCheck +{ + public MotionE(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition()) { + if (this.data.getActionProcessor().isHasSlowness() || this.data.getPlayer().getWalkSpeed() > 0.25) { + return; + } + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double modulo = 0.1 % (deltaXZ % 0.1); + final boolean exempt = this.isExempt(ExemptType.TELEPORT, ExemptType.RIPTIDE, ExemptType.GLIDING, ExemptType.STAIRS, ExemptType.VELOCITY, ExemptType.JOINED, ExemptType.FLIGHT, ExemptType.CREATIVE, ExemptType.VEHICLE, ExemptType.WORLD_CHANGE, ExemptType.DOLPHINS_GRACE, ExemptType.SOUL_SPEED, ExemptType.SLIME, ExemptType.HONEY, ExemptType.DEATH, ExemptType.RIPTIDE, ExemptType.SLEEPING, ExemptType.LEVITATION, ExemptType.LIQUID, ExemptType.ANVIL, ExemptType.SERVER_POSITION, ExemptType.PISTON, ExemptType.WEB); + final boolean invalid = deltaXZ > 0.11 && modulo < 1.0E-8; + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaXZ=" + deltaXZ + " modulo=" + modulo); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/motion/MotionG.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/motion/MotionG.java new file mode 100644 index 0000000..3da0f26 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/motion/MotionG.java @@ -0,0 +1,123 @@ +package me.frep.vulcan.spigot.check.impl.movement.motion; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Motion", type = 'G', complexType = "Additional velocity", description = "Took additional velocity.") +public class MotionG extends AbstractCheck +{ + public MotionG(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting()) { + if (this.data.getPlayer().hasMetadata("ThrownByBoss")) { + return; + } + if (this.data.getActionProcessor().getTicksExisted() < 30) { + return; + } + final int sinceFireDamageTicks = this.data.getActionProcessor().getSinceFireDamageTicks(); + final int sinceAttackDamageTicks = this.data.getActionProcessor().getSinceAttackDamageTicks(); + final int sinceLavaDamageTicks = this.data.getActionProcessor().getSinceLavaDamageTicks(); + final int sinceFallDamageTicks = this.data.getActionProcessor().getSinceFallDamageTicks(); + final int sinceMagicDamageTicks = this.data.getActionProcessor().getSinceMagicDamageTicks(); + final int sinceProjectileDamageTicks = this.data.getActionProcessor().getSinceProjectileDamageTicks(); + final int sinceContactDamageTicks = this.data.getActionProcessor().getSinceContactDamageTicks(); + final int sinceIronGolemDamageTicks = this.data.getActionProcessor().getSinceIronGolemDamageTicks(); + final int sinceHoglinDamageTicks = this.data.getActionProcessor().getSinceHoglinDamageTicks(); + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final boolean exempt = this.isExempt(ExemptType.JOINED, ExemptType.TELEPORT, ExemptType.RIPTIDE, ExemptType.VEHICLE, ExemptType.EXPLOSION, ExemptType.HONEY, ExemptType.GLIDING, ExemptType.ELYTRA, ExemptType.LEVITATION, ExemptType.SLAB, ExemptType.STAIRS, ExemptType.MYTHIC_MOB, ExemptType.RESPAWN, ExemptType.JUMP_BOOST_RAN_OUT, ExemptType.BOAT, ExemptType.BUBBLE_COLUMN, ExemptType.WALL, ExemptType.CREATIVE, ExemptType.SPECTATOR, ExemptType.SHULKER, ExemptType.SHULKER_BOX, ExemptType.ANVIL, ExemptType.SLIME, ExemptType.PISTON, ExemptType.TURTLE_EGG, ExemptType.DOOR, ExemptType.DEATH, ExemptType.FENCE_GATE, ExemptType.ENDER_PEARL, ExemptType.PLACED_SLIME, ExemptType.BUKKIT_VELOCITY, ExemptType.DRAGON_DAMAGE, ExemptType.BLOCK_BREAK, ExemptType.FISHING_ROD, ExemptType.SLEEPING, ExemptType.SERVER_POSITION, ExemptType.BED, ExemptType.FLIGHT); + final boolean fireball = this.isExempt(ExemptType.FIREBALL); + double max = 0.42f + this.data.getActionProcessor().getJumpBoostAmplifier() * 1.25f; + if (fireball) { + max += 0.4000000059604645; + } + final double diff = deltaY - max; + if (sinceFireDamageTicks < 20) { + if (deltaY > max && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER || diff > 5.0) { + this.fail("[Fire] deltaY=" + deltaY + " max=" + max + " ticks=" + sinceFireDamageTicks); + } + } + else { + this.decayBuffer(); + } + } + else if (sinceAttackDamageTicks < 20) { + max += 0.3499999940395355; + if (sinceIronGolemDamageTicks < 20) { + max += 0.20000000298023224; + } + if (sinceHoglinDamageTicks < 20) { + max += 0.25; + } + if (deltaY > max && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER || diff > 5.0) { + this.fail("[Attack] deltaY=" + deltaY + " max=" + max + " ticks=" + sinceAttackDamageTicks); + } + } + else { + this.decayBuffer(); + } + } + else if (sinceLavaDamageTicks < 20) { + if (deltaY > max && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER || diff > 5.0) { + this.fail("[Lava] deltaY=" + deltaY + " max=" + max + " ticks" + sinceLavaDamageTicks); + } + } + else { + this.decayBuffer(); + } + } + else if (sinceFallDamageTicks < 20) { + if (deltaY > max && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER || diff > 5.0) { + this.fail("[Fall Damage] deltaY=" + deltaY + " max=" + max + " ticks=" + sinceFallDamageTicks); + } + } + else { + this.decayBuffer(); + } + } + else if (sinceMagicDamageTicks < 20) { + if (deltaY > max && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER || diff > 5.0) { + this.fail("[Magic] deltaY=" + deltaY + " max=" + max + " ticks=" + sinceMagicDamageTicks); + } + } + else { + this.decayBuffer(); + } + } + else if (sinceProjectileDamageTicks < 20) { + final boolean wither = this.data.getActionProcessor().getSinceWitherDamageTicks() < 100; + max += 0.02; + if (deltaY > max && !exempt && !wither) { + if (this.increaseBuffer() > this.MAX_BUFFER || diff > 5.0) { + this.fail("[Projectile] deltaY=" + deltaY + " max=" + max + " ticks=" + sinceProjectileDamageTicks); + } + } + else { + this.decayBuffer(); + } + } + else if (sinceContactDamageTicks < 20) { + if (deltaY > max && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER || diff > 5.0) { + this.fail("[Magic] deltaY=" + deltaY + " max=" + max + " ticks=" + sinceContactDamageTicks); + } + } + else { + this.decayBuffer(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/motion/MotionH.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/motion/MotionH.java new file mode 100644 index 0000000..f11775b --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/motion/MotionH.java @@ -0,0 +1,43 @@ +package me.frep.vulcan.spigot.check.impl.movement.motion; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Motion", type = 'H', complexType = "Velocity", description = "Took additional explosion.", experimental = true) +public class MotionH extends AbstractCheck +{ + public MotionH(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting()) { + if (this.data.getPlayer().hasMetadata("ThrownByBoss") || this.data.getActionProcessor().getSinceExplosionTicks() > 50) { + return; + } + if (this.data.getActionProcessor().getExplosionY() < 0.01 || this.data.getActionProcessor().getJumpBoostAmplifier() > 10) { + return; + } + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final boolean exempt = this.isExempt(ExemptType.JOINED, ExemptType.TELEPORT, ExemptType.RIPTIDE, ExemptType.VEHICLE, ExemptType.HONEY, ExemptType.GLIDING, ExemptType.ELYTRA, ExemptType.LEVITATION, ExemptType.SLAB, ExemptType.STAIRS, ExemptType.MYTHIC_MOB, ExemptType.RESPAWN, ExemptType.JUMP_BOOST_RAN_OUT, ExemptType.BOAT, ExemptType.BUBBLE_COLUMN, ExemptType.WALL, ExemptType.CREATIVE, ExemptType.SPECTATOR, ExemptType.SHULKER, ExemptType.SHULKER_BOX, ExemptType.ANVIL, ExemptType.SLIME, ExemptType.PISTON, ExemptType.TURTLE_EGG, ExemptType.DOOR, ExemptType.DEATH, ExemptType.FENCE_GATE, ExemptType.ENDER_PEARL, ExemptType.PLACED_SLIME, ExemptType.BUKKIT_VELOCITY, ExemptType.DRAGON_DAMAGE, ExemptType.BLOCK_BREAK, ExemptType.FISHING_ROD, ExemptType.SLEEPING, ExemptType.SERVER_POSITION, ExemptType.BED, ExemptType.FLIGHT); + final boolean fireball = this.isExempt(ExemptType.FIREBALL); + double max = Math.abs(this.data.getActionProcessor().getExplosionY()) + this.data.getActionProcessor().getJumpBoostAmplifier() * 1.25f + 0.2; + if (fireball) { + max += 0.44999998807907104; + } + final double diff = deltaY - max; + if (diff > 0.1 && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaY=" + deltaY + " velocity=" + this.data.getActionProcessor().getExplosionY()); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/nosaddle/NoSaddleA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/nosaddle/NoSaddleA.java new file mode 100644 index 0000000..c3b8bf0 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/nosaddle/NoSaddleA.java @@ -0,0 +1,55 @@ +package me.frep.vulcan.spigot.check.impl.movement.nosaddle; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.Plugin; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.Bukkit; +import me.frep.vulcan.spigot.config.Config; +import org.bukkit.attribute.Attribute; +import org.bukkit.entity.Horse; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "No Saddle", type = 'A', complexType = "Spoof", description = "Controlling an entity without a saddle.") +public class NoSaddleA extends AbstractCheck +{ + public NoSaddleA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isVehicleMove()) { + if (ServerUtil.isLowerThan1_9()) { + return; + } + final boolean vehicleHorse = this.data.getPlayer().getVehicle() instanceof Horse; + final double deltaXZ = this.data.getPositionProcessor().getVehicleDeltaXZ(); + if (vehicleHorse) { + final Horse horse = (Horse)this.data.getPlayer().getVehicle(); + if (horse == null || horse.isLeashed()) { + return; + } + final double maxSpeed = horse.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getBaseValue() * 2.25 + 0.1; + final ItemStack saddle = horse.getInventory().getSaddle(); + final double difference = maxSpeed - deltaXZ; + final boolean invalid = saddle == null && difference < 0.3 && deltaXZ > 0.1; + final int vehicleTicks = this.data.getPositionProcessor().getVehicleTicks(); + if (invalid && vehicleTicks > 5) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("diff=" + difference + " deltaXZ=" + deltaXZ); + if (Config.NO_SADDLE_A_KICKOUT) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().leaveVehicle()); + } + } + } + else { + this.decayBuffer(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/noslow/NoSlowA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/noslow/NoSlowA.java new file mode 100644 index 0000000..a0ac2ba --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/noslow/NoSlowA.java @@ -0,0 +1,34 @@ +package me.frep.vulcan.spigot.check.impl.movement.noslow; + +import io.github.retrooper.packetevents.packetwrappers.play.in.blockdig.WrappedPacketInBlockDig; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "No Slow", type = 'A', complexType = "Packet", description = "Placing while digging") +public class NoSlowA extends AbstractCheck +{ + public NoSlowA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isBlockDig()) { + final WrappedPacketInBlockDig wrapper = this.data.getBlockDigWrapper(); + final boolean placing = this.data.getActionProcessor().isPlacing(); + final boolean exempt = this.isExempt(ExemptType.CLIENT_VERSION, ExemptType.SERVER_VERSION); + final boolean action = wrapper.getDigType() == WrappedPacketInBlockDig.PlayerDigType.RELEASE_USE_ITEM; + if (placing && action && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail(); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/noslow/NoSlowB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/noslow/NoSlowB.java new file mode 100644 index 0000000..7590479 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/noslow/NoSlowB.java @@ -0,0 +1,37 @@ +package me.frep.vulcan.spigot.check.impl.movement.noslow; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "No Slow", type = 'B', complexType = "Soul Sand", description = "Moving too quickly on Soul Sand.") +public class NoSlowB extends AbstractCheck +{ + public NoSlowB(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition()) { + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double max = PlayerUtil.getBaseSpeed(this.data, 0.2f) + this.data.getActionProcessor().getSpeedAmplifier() * 0.0625f; + final boolean onSoulSand = this.data.getPositionProcessor().isOnSoulSand(); + final boolean onGround = this.data.getPositionProcessor().isMathematicallyOnGround(); + final boolean exempt = this.isExempt(ExemptType.FLIGHT, ExemptType.CREATIVE, ExemptType.VELOCITY, ExemptType.TELEPORT, ExemptType.ENDER_PEARL, ExemptType.CHORUS_FRUIT, ExemptType.SOUL_SPEED, ExemptType.ELYTRA, ExemptType.RIPTIDE, ExemptType.HIGH_SPEED, ExemptType.DEPTH_STRIDER, ExemptType.ATTRIBUTE_MODIFIER); + final boolean invalid = onSoulSand && deltaXZ > max && onGround; + final boolean walkSpeed = this.data.getPositionProcessor().getWalkSpeed() > 0.11f || this.data.getActionProcessor().getGenericMovementSpeed() > 0.10999999940395355; + if (invalid && !exempt && !walkSpeed) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaXZ=" + deltaXZ + " max=" + max); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/noslow/NoSlowC.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/noslow/NoSlowC.java new file mode 100644 index 0000000..0756f30 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/noslow/NoSlowC.java @@ -0,0 +1,35 @@ +package me.frep.vulcan.spigot.check.impl.movement.noslow; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "No Slow", type = 'C', complexType = "Web", description = "Moving too quickly in a web.") +public class NoSlowC extends AbstractCheck +{ + public NoSlowC(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition()) { + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double max = PlayerUtil.getBaseSpeed(this.data, 0.09f); + final boolean inWeb = this.data.getPositionProcessor().isInWeb(); + final boolean exempt = this.isExempt(ExemptType.FLIGHT, ExemptType.CREATIVE, ExemptType.VELOCITY, ExemptType.TELEPORT, ExemptType.ENDER_PEARL, ExemptType.CHORUS_FRUIT, ExemptType.RIPTIDE, ExemptType.ELYTRA, ExemptType.GLIDING, ExemptType.DEPTH_STRIDER, ExemptType.SERVER_POSITION_FAST, ExemptType.ELYTRA, ExemptType.GLIDING, ExemptType.ATTRIBUTE_MODIFIER); + final boolean invalid = inWeb && deltaXZ > max; + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaXZ=" + deltaXZ + " max=" + max); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/speed/SpeedA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/speed/SpeedA.java new file mode 100644 index 0000000..a3d78a4 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/speed/SpeedA.java @@ -0,0 +1,44 @@ +package me.frep.vulcan.spigot.check.impl.movement.speed; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Speed", type = 'A', complexType = "Friction", description = "Invalid friction.") +public class SpeedA extends AbstractCheck +{ + public SpeedA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting() && !this.fuckedPosition()) { + if (this.data.getActionProcessor().getSinceCrystalDamageTicks() < 3) { + return; + } + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double lastDeltaXZ = this.data.getPositionProcessor().getLastDeltaXZ(); + final boolean sprinting = true; + final double prediction = lastDeltaXZ * 0.9100000262260437 + 0.026; + final double difference = deltaXZ - prediction; + final int airTicks = this.data.getPositionProcessor().getClientAirTicks(); + final boolean piston = this.data.getPositionProcessor().getSinceAroundPistonTicks() < 15; + final boolean velocity = this.data.getVelocityProcessor().getTransactionFlyingTicks() < 3; + final boolean exempt = this.isExempt(ExemptType.ILLEGAL_BLOCK, ExemptType.FULLY_STUCK, ExemptType.DOLPHINS_GRACE, ExemptType.WEB, ExemptType.SLEEPING, ExemptType.DEPTH_STRIDER, ExemptType.VOID, ExemptType.WORLD_CHANGE, ExemptType.CHUNK, ExemptType.JOINED, ExemptType.ELYTRA, ExemptType.ENTITY_COLLISION, ExemptType.ANVIL, ExemptType.TRAPDOOR, ExemptType.SPECTATOR, ExemptType.PARTIALLY_STUCK, ExemptType.FENCE_GATE, ExemptType.FROZEN, ExemptType.CHORUS_FRUIT, ExemptType.BLOCK_BREAK, ExemptType.CANCELLED_MOVE) || this.data.getPositionProcessor().isExemptFlight() || this.data.getPositionProcessor().isExemptGliding() || this.data.getPositionProcessor().isExemptCreative() || this.data.getPositionProcessor().isExemptTeleport() || this.data.getPositionProcessor().isExemptLiquid() || this.data.getPositionProcessor().isExemptRiptide() || this.data.getPositionProcessor().isExemptEnderPearl() || this.data.getPositionProcessor().isExemptVehicle(); + final boolean explosion = this.data.getActionProcessor().getSinceExplosionDamageTicks() < 10; + if (airTicks > 2 && !velocity && !exempt && !piston && deltaXZ > 0.25 && !explosion) { + if (difference > 1.0E-5) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("difference=" + difference + " ticks=" + airTicks + " deltaXZ=" + deltaXZ); + } + } + else { + this.decayBuffer(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/speed/SpeedB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/speed/SpeedB.java new file mode 100644 index 0000000..7f2c0b5 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/speed/SpeedB.java @@ -0,0 +1,440 @@ +package me.frep.vulcan.spigot.check.impl.movement.speed; + +import me.frep.vulcan.spigot.data.processor.VelocityProcessor; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Speed", type = 'B', complexType = "Ground", description = "Moving too quickly on the ground.") +public class SpeedB extends AbstractCheck +{ + public SpeedB(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting() && !this.fuckedPosition()) { + if (this.data.getActionProcessor().getJumpBoostAmplifier() > 50) { + return; + } + final boolean stuck = this.data.getPositionProcessor().isFullyStuck() || this.data.getPositionProcessor().isPartiallyStuck(); + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final int groundTicks = this.data.getPositionProcessor().getClientGroundTicks(); + final int sinceCollidingVerticallyTicks = this.data.getPositionProcessor().getSinceCollidingVerticallyTicks(); + final int sinceIceTicks = this.data.getPositionProcessor().getSinceIceTicks(); + final int sinceSlimeTicks = this.data.getPositionProcessor().getSinceNearSlimeTicks(); + final int sinceVelocityTicks = this.data.getVelocityProcessor().getTransactionFlyingTicks(); + final int sinceTrapdoorTicks = this.data.getPositionProcessor().getSinceTrapdoorTicks(); + final int sinceNearFenceTicks = this.data.getPositionProcessor().getSinceNearFenceTicks(); + final int sinceNearBedTicks = this.data.getPositionProcessor().getSinceNearBedTicks(); + final boolean wasCollidingVertically = sinceCollidingVerticallyTicks < 45; + final boolean wasOnIce = sinceIceTicks < 60; + final boolean wasNearBed = sinceNearBedTicks < 30; + final boolean nearStair = this.data.getPositionProcessor().isNearStair(); + final boolean wasOnSlime = sinceSlimeTicks < 30; + final boolean wasNearTrapdoor = sinceTrapdoorTicks < 40; + final boolean depthStrider = this.isExempt(ExemptType.DEPTH_STRIDER); + final boolean nearSlab = this.data.getPositionProcessor().isNearSlab(); + final boolean wasNearFence = sinceNearFenceTicks < 20; + final boolean soulSpeed = this.data.getPositionProcessor().getSinceSoulSpeedTicks() < 30; + final boolean wasNearSlime = this.data.getPositionProcessor().getSinceNearSlimeTicks() < 30; + double maxSpeed = PlayerUtil.getBaseGroundSpeed(this.data); + switch (groundTicks) { + case 0: { + maxSpeed += 0.323; + if (wasCollidingVertically && !stuck) { + maxSpeed += 0.076; + } + if (wasOnIce) { + maxSpeed += 0.08; + } + if (nearStair) { + maxSpeed += 0.35; + } + if (wasCollidingVertically && wasOnIce) { + maxSpeed += 0.35; + } + if (wasOnSlime) { + maxSpeed += 0.05; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.6; + } + if (nearSlab) { + maxSpeed += 0.04; + } + if (sinceIceTicks == 0 && nearSlab) { + maxSpeed += 0.1; + } + if (wasNearTrapdoor) { + maxSpeed += 0.1; + } + if (wasNearFence) { + maxSpeed += 0.1; + } + if (deltaY == 0.41999998688697815) { + maxSpeed += 0.03; + break; + } + break; + } + case 1: { + maxSpeed += 0.025; + if (wasCollidingVertically && !stuck) { + maxSpeed += 0.0728; + } + if (wasOnIce) { + maxSpeed += 0.1; + } + if (nearStair) { + maxSpeed += 0.35; + } + if (wasCollidingVertically && wasOnIce) { + maxSpeed += 0.45; + } + if (wasOnSlime) { + maxSpeed += 0.05; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.55; + } + if (nearSlab) { + maxSpeed += 0.15; + } + if (wasNearTrapdoor) { + maxSpeed += 0.1; + } + if (wasNearFence) { + maxSpeed += 0.1; + break; + } + break; + } + case 2: { + maxSpeed += 0.134; + if (wasCollidingVertically && !stuck) { + maxSpeed += 0.06694; + } + if (wasOnIce) { + maxSpeed += 0.08; + } + if (wasNearBed) { + maxSpeed += 0.04; + } + if (nearStair) { + maxSpeed += 0.35; + } + if (wasCollidingVertically && wasOnIce) { + maxSpeed += 0.4; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.55; + } + if (nearSlab) { + maxSpeed += 0.15; + } + if (wasNearTrapdoor) { + maxSpeed += 0.1; + } + if (sinceIceTicks == 0 && nearSlab) { + maxSpeed += 0.005; + } + if (wasNearFence) { + maxSpeed += 0.1; + break; + } + break; + } + case 3: { + maxSpeed += 0.0693; + if (wasCollidingVertically && !stuck) { + maxSpeed += 0.036; + } + if (wasOnIce) { + maxSpeed += 0.045; + } + if (nearStair) { + maxSpeed += 0.35; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.35; + } + if (wasCollidingVertically && wasOnIce) { + maxSpeed += 0.35; + } + if (nearSlab) { + maxSpeed += 0.04; + } + if (wasNearBed) { + maxSpeed += 0.04; + } + if (wasNearFence) { + maxSpeed += 0.1; + } + if (wasNearTrapdoor) { + maxSpeed += 0.1; + break; + } + break; + } + case 4: { + maxSpeed += 0.035; + if (wasCollidingVertically && !stuck) { + maxSpeed += 0.0211; + } + if (wasOnIce) { + maxSpeed += 0.03; + } + if (nearStair) { + maxSpeed += 0.35; + } + if (wasNearTrapdoor) { + maxSpeed += 0.1; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.35; + } + if (wasCollidingVertically && wasOnIce) { + maxSpeed += 0.35; + } + if (nearSlab) { + maxSpeed += 0.04; + break; + } + break; + } + case 5: { + maxSpeed += 0.0205; + if (wasCollidingVertically && !stuck) { + maxSpeed += 0.0231; + } + if (wasOnIce) { + maxSpeed += 0.03; + } + if (nearStair) { + maxSpeed += 0.35; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.35; + } + if (nearSlab) { + maxSpeed += 0.04; + break; + } + break; + } + case 6: { + maxSpeed += 0.009; + if (wasCollidingVertically && !stuck) { + maxSpeed += 0.0027; + } + if (wasOnIce) { + maxSpeed += 0.02; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.35; + } + if (nearSlab) { + maxSpeed += 0.04; + break; + } + break; + } + case 7: { + maxSpeed += 0.005; + if (wasOnIce) { + maxSpeed += 0.02; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.1; + break; + } + break; + } + case 8: { + maxSpeed += 0.003; + if (wasOnIce) { + maxSpeed += 0.02; + } + if (sinceIceTicks == 0 && nearSlab) { + maxSpeed += 0.02; + break; + } + break; + } + case 9: { + maxSpeed += 0.0025; + if (wasOnIce) { + maxSpeed += 0.02; + break; + } + break; + } + } + if (sinceIceTicks == 0) { + if (groundTicks > 2 && groundTicks < 9) { + maxSpeed += 0.09; + } + else if (groundTicks >= 9 && groundTicks < 15) { + maxSpeed += 0.09; + } + else if (groundTicks >= 15) { + maxSpeed += 0.09; + } + } + if (this.isExempt(ExemptType.FARMLAND)) { + maxSpeed += 0.05; + } + if (sinceIceTicks < 30 && groundTicks >= 5 && groundTicks <= 25 && wasCollidingVertically) { + maxSpeed += 0.15; + } + if (this.isExempt(ExemptType.CANCELLED_PLACE)) { + maxSpeed += 0.08; + } + if (sinceIceTicks < 30 && groundTicks > 8) { + maxSpeed += 0.15; + } + if (depthStrider) { + maxSpeed += 0.1; + } + if (ServerUtil.isHigherThan1_16() && soulSpeed && this.data.getActionProcessor().getSpeedAmplifier() > 3) { + maxSpeed += 1.25; + } + if (ServerUtil.isHigherThan1_16() && soulSpeed) { + maxSpeed += 0.5; + } + if (wasOnIce && wasNearSlime) { + maxSpeed += 0.35; + } + if (wasNearSlime && wasCollidingVertically) { + maxSpeed += 0.1; + } + final VelocityProcessor.VelocitySnapshot snapshot = this.data.getVelocityProcessor().getSnapshot(); + double velocityXZ = this.data.getVelocityProcessor().getVelocityXZ(); + if (snapshot != null) { + final double velocityX = snapshot.getVelocity().getX(); + final double velocityZ = snapshot.getVelocity().getZ(); + velocityXZ = MathUtil.hypot(velocityX, velocityZ); + } + switch (sinceVelocityTicks) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: { + maxSpeed += velocityXZ + 0.05; + break; + } + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: { + maxSpeed += velocityXZ * 0.75; + break; + } + case 16: + case 17: + case 18: + case 19: + case 20: { + maxSpeed += velocityXZ * 0.6; + break; + } + case 21: + case 22: + case 23: + case 24: + case 25: { + maxSpeed += velocityXZ * 0.5; + break; + } + case 26: + case 27: + case 28: + case 29: + case 30: { + maxSpeed += velocityXZ * 0.35; + break; + } + case 31: + case 32: + case 33: + case 34: + case 35: { + maxSpeed += velocityXZ * 0.25; + break; + } + case 36: + case 37: + case 38: + case 39: + case 40: { + maxSpeed += velocityXZ * 0.1; + break; + } + } + if (this.data.getPositionProcessor().getSinceAroundSlimeTicks() < 25) { + maxSpeed += 1.5; + } + if (ServerUtil.isHigherThan1_9() && Config.ENTITY_COLLISION_FIX && this.data.getPositionProcessor().getSinceEntityCollisionTicks() < 20) { + maxSpeed += 0.1; + } + if (this.data.getActionProcessor().getSinceIcePlaceTicks() < 35) { + maxSpeed += 0.2; + } + if (this.isExempt(ExemptType.PISTON)) { + maxSpeed += 0.325; + } + if (this.data.getPositionProcessor().getSinceAroundSlabTicks() < 5) { + maxSpeed += 0.025; + } + if (this.isExempt(ExemptType.BUKKIT_VELOCITY)) { + maxSpeed += velocityXZ * 2.0; + } + if (this.isExempt(ExemptType.SPEED_RAN_OUT)) { + ++maxSpeed; + } + if (this.isExempt(ExemptType.SNOW)) { + maxSpeed += 0.05; + } + if (this.data.getActionProcessor().getSinceRavagerDamageTicks() < 30) { + maxSpeed += 2.0; + } + if (this.data.getActionProcessor().getSinceCrystalDamageTicks() < 5) { + ++maxSpeed; + } + else if (this.data.getActionProcessor().getSinceCrystalDamageTicks() > 5 && this.data.getActionProcessor().getSinceCrystalDamageTicks() < 25) { + maxSpeed += 0.75; + } + if (this.data.getPositionProcessor().isNearPressurePlate()) { + maxSpeed += 0.08; + } + final double difference = deltaXZ - maxSpeed; + final boolean exempt = this.isExempt(ExemptType.FLIGHT, ExemptType.JOINED, ExemptType.CREATIVE, ExemptType.SHULKER, ExemptType.SHULKER_BOX, ExemptType.DOLPHINS_GRACE, ExemptType.TELEPORT, ExemptType.ILLEGAL_BLOCK, ExemptType.GLIDING, ExemptType.CHUNK, ExemptType.RIPTIDE, ExemptType.VEHICLE, ExemptType.BOAT, ExemptType.FISHING_ROD, ExemptType.ELYTRA, ExemptType.ENTITY_CRAM_FIX, ExemptType.DEATH, ExemptType.SLEEPING, ExemptType.ENDER_PEARL, ExemptType.FROZEN, ExemptType.CHORUS_FRUIT, ExemptType.SPECTATOR, ExemptType.WORLD_CHANGE, ExemptType.ATTRIBUTE_MODIFIER, ExemptType.ANVIL, ExemptType.CANCELLED_MOVE); + final boolean invalid = difference > Config.SPEED_B_MIN_DIFFERENCE && groundTicks >= 0; + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER || (difference > 0.5 && difference < 100.0 && !this.isExempt(ExemptType.SERVER_POSITION, ExemptType.CHORUS_FRUIT))) { + this.fail("speed=" + deltaXZ + " max=" + maxSpeed + " diff=" + difference + " ticks=" + groundTicks + " deltaY=" + deltaY); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/speed/SpeedC.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/speed/SpeedC.java new file mode 100644 index 0000000..ed482de --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/speed/SpeedC.java @@ -0,0 +1,183 @@ +package me.frep.vulcan.spigot.check.impl.movement.speed; + +import me.frep.vulcan.spigot.data.processor.VelocityProcessor; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Speed", type = 'C', complexType = "Air", description = "Moving too quickly in the air.") +public class SpeedC extends AbstractCheck +{ + public SpeedC(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting() && !this.fuckedPosition()) { + if (this.data.getActionProcessor().getJumpBoostAmplifier() > 50) { + return; + } + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final int airTicks = this.data.getPositionProcessor().getClientAirTicks(); + final boolean ice = this.data.getPositionProcessor().getSinceIceTicks() < 40; + final boolean collidingVertically = this.data.getPositionProcessor().getSinceCollidingVerticallyTicks() < 30; + final boolean slime = this.data.getPositionProcessor().getSinceNearSlimeTicks() < 30; + final boolean soulSpeed = this.data.getPositionProcessor().getSinceSoulSpeedTicks() < 30; + double maxSpeed = PlayerUtil.getBaseSpeed(this.data); + if (collidingVertically) { + maxSpeed += 0.1; + } + if (this.isExempt(ExemptType.CANCELLED_PLACE)) { + maxSpeed += 0.1; + } + if (this.data.getPositionProcessor().getSinceAroundSlimeTicks() < 15) { + maxSpeed += 0.6; + } + if (airTicks == 2 && this.data.getPositionProcessor().getSinceCollidingVerticallyTicks() < 50 && deltaY == -0.07840000152587834) { + maxSpeed += 0.165; + } + if (ice) { + maxSpeed += 0.25; + } + if (collidingVertically && ice) { + maxSpeed += 0.3; + } + if (this.isExempt(ExemptType.STAIRS)) { + maxSpeed += 0.05; + } + if (slime) { + maxSpeed += 0.1; + } + if (ServerUtil.isHigherThan1_16() && soulSpeed) { + maxSpeed += 0.3; + } + final int sinceVelocityTicks = this.data.getVelocityProcessor().getTransactionFlyingTicks(); + final VelocityProcessor.VelocitySnapshot snapshot = this.data.getVelocityProcessor().getSnapshot(); + double velocityXZ = this.data.getVelocityProcessor().getVelocityXZ(); + if (snapshot != null) { + final double velocityX = snapshot.getVelocity().getX(); + final double velocityZ = snapshot.getVelocity().getZ(); + velocityXZ = MathUtil.hypot(velocityX, velocityZ); + } + switch (sinceVelocityTicks) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: { + maxSpeed += velocityXZ + 0.05; + break; + } + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: { + maxSpeed += velocityXZ * 0.75; + break; + } + case 16: + case 17: + case 18: + case 19: + case 20: { + maxSpeed += velocityXZ * 0.6; + break; + } + case 21: + case 22: + case 23: + case 24: + case 25: { + maxSpeed += velocityXZ * 0.5; + break; + } + case 26: + case 27: + case 28: + case 29: + case 30: { + maxSpeed += velocityXZ * 0.35; + break; + } + case 31: + case 32: + case 33: + case 34: + case 35: { + maxSpeed += velocityXZ * 0.25; + break; + } + case 36: + case 37: + case 38: + case 39: + case 40: { + maxSpeed += velocityXZ * 0.1; + break; + } + } + if (ServerUtil.isHigherThan1_13() && this.data.getPositionProcessor().getSinceHoneyTicks() < 20) { + maxSpeed += 0.125; + } + if (this.data.getActionProcessor().getSinceIcePlaceTicks() < 40) { + maxSpeed += 0.2; + } + if (this.isExempt(ExemptType.FARMLAND)) { + maxSpeed += 0.025; + } + if (ServerUtil.isHigherThan1_9() && Config.ENTITY_COLLISION_FIX && this.data.getPositionProcessor().getSinceEntityCollisionTicks() < 20) { + maxSpeed += 0.1; + } + if (this.isExempt(ExemptType.PISTON)) { + maxSpeed += 0.325; + } + if (this.isExempt(ExemptType.BUKKIT_VELOCITY)) { + maxSpeed += velocityXZ * 2.0; + } + if (this.isExempt(ExemptType.SPEED_RAN_OUT)) { + ++maxSpeed; + } + if (this.isExempt(ExemptType.SNOW)) { + maxSpeed += 0.05; + } + if (this.data.getActionProcessor().getSinceFireballDamageTicks() < 30) { + maxSpeed += 0.75; + } + if (this.data.getActionProcessor().getSinceRavagerDamageTicks() < 30) { + maxSpeed += 2.0; + } + if (this.data.getActionProcessor().getSinceCrystalDamageTicks() < 5) { + ++maxSpeed; + } + else if (this.data.getActionProcessor().getSinceCrystalDamageTicks() > 5 && this.data.getActionProcessor().getSinceCrystalDamageTicks() < 25) { + maxSpeed += 0.5; + } + final boolean exempt = this.isExempt(ExemptType.JOINED, ExemptType.ILLEGAL_BLOCK, ExemptType.RIPTIDE, ExemptType.SHULKER, ExemptType.CHORUS_FRUIT, ExemptType.GLIDING, ExemptType.FLIGHT, ExemptType.CREATIVE, ExemptType.VEHICLE, ExemptType.SHULKER_BOX, ExemptType.CHUNK, ExemptType.FISHING_ROD, ExemptType.DOLPHINS_GRACE, ExemptType.ENDER_PEARL, ExemptType.TELEPORT, ExemptType.WORLD_CHANGE, ExemptType.ELYTRA, ExemptType.FROZEN, ExemptType.DEATH, ExemptType.SLEEPING, ExemptType.BOAT, ExemptType.SPECTATOR, ExemptType.ATTRIBUTE_MODIFIER, ExemptType.ANVIL, ExemptType.FULLY_STUCK, ExemptType.PARTIALLY_STUCK, ExemptType.CANCELLED_MOVE, ExemptType.ENTITY_CRAM_FIX); + final double difference = deltaXZ - maxSpeed; + final boolean invalid = airTicks > 1 && difference > Config.SPEED_C_MIN_DIFFERENCE; + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER || (difference > 0.5 && difference < 100.0 && !this.isExempt(ExemptType.SERVER_POSITION_FAST))) { + this.fail("speed=" + deltaXZ + " max=" + maxSpeed + " diff=" + difference + " ticks=" + airTicks + " deltaY=" + deltaY); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/speed/SpeedD.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/speed/SpeedD.java new file mode 100644 index 0000000..26a565c --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/speed/SpeedD.java @@ -0,0 +1,466 @@ +package me.frep.vulcan.spigot.check.impl.movement.speed; + +import me.frep.vulcan.spigot.data.processor.VelocityProcessor; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Speed", type = 'D', complexType = "Ground", description = "Moving too quickly on the ground.") +public class SpeedD extends AbstractCheck +{ + public SpeedD(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting() && !this.fuckedPosition()) { + if (this.data.getActionProcessor().getJumpBoostAmplifier() > 50) { + return; + } + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final boolean stuck = this.data.getPositionProcessor().isFullyStuck() || this.data.getPositionProcessor().isPartiallyStuck(); + final int groundTicks = this.data.getPositionProcessor().getServerGroundTicks(); + final int sinceCollidingVerticallyTicks = this.data.getPositionProcessor().getSinceCollidingVerticallyTicks(); + final int sinceIceTicks = this.data.getPositionProcessor().getSinceIceTicks(); + final int sinceSlimeTicks = this.data.getPositionProcessor().getSinceNearSlimeTicks(); + final int sinceVelocityTicks = this.data.getVelocityProcessor().getTransactionFlyingTicks(); + final int sinceTrapdoorTicks = this.data.getPositionProcessor().getSinceTrapdoorTicks(); + final int sinceNearFenceTicks = this.data.getPositionProcessor().getSinceNearFenceTicks(); + final int sinceNearBedTicks = this.data.getPositionProcessor().getSinceNearBedTicks(); + final boolean wasCollidingVertically = sinceCollidingVerticallyTicks < 45; + final boolean wasOnIce = sinceIceTicks < 60; + final boolean wasNearBed = sinceNearBedTicks < 30; + final boolean nearStair = this.data.getPositionProcessor().isNearStair() || this.data.getPositionProcessor().getSinceNearStairTicks() < 20; + final boolean wasOnSlime = sinceSlimeTicks < 30; + final boolean wasNearTrapdoor = sinceTrapdoorTicks < 40; + final boolean depthStrider = this.isExempt(ExemptType.DEPTH_STRIDER); + final boolean nearSlab = this.data.getPositionProcessor().isNearSlab(); + final boolean wasNearFence = sinceNearFenceTicks < 20; + final boolean soulSpeed = this.data.getPositionProcessor().getSinceSoulSpeedTicks() < 30; + final boolean wasNearSlime = this.data.getPositionProcessor().getSinceNearSlimeTicks() < 30; + double maxSpeed = PlayerUtil.getBaseGroundSpeed(this.data); + switch (groundTicks) { + case 0: { + maxSpeed += 0.323; + if (wasCollidingVertically && !stuck) { + maxSpeed += 0.076; + } + if (wasOnIce) { + maxSpeed += 0.08; + } + if (nearStair) { + maxSpeed += 0.35; + } + if (wasCollidingVertically && wasOnIce) { + maxSpeed += 0.35; + } + if (wasOnSlime) { + maxSpeed += 0.05; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.6; + } + if (nearSlab) { + maxSpeed += 0.04; + } + if (sinceIceTicks == 0 && nearSlab) { + maxSpeed += 0.1; + } + if (wasNearTrapdoor) { + maxSpeed += 0.1; + } + if (wasNearFence) { + maxSpeed += 0.1; + } + if (deltaY == 0.41999998688697815) { + maxSpeed += 0.03; + break; + } + break; + } + case 1: { + maxSpeed += 0.025; + if (wasCollidingVertically && !stuck) { + maxSpeed += 0.0728; + } + if (wasOnIce) { + maxSpeed += 0.1; + } + if (nearStair) { + maxSpeed += 0.35; + } + if (wasCollidingVertically && wasOnIce) { + maxSpeed += 0.45; + } + if (wasOnSlime) { + maxSpeed += 0.05; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.55; + } + if (nearSlab) { + maxSpeed += 0.15; + } + if (wasNearTrapdoor) { + maxSpeed += 0.1; + } + if (wasNearFence) { + maxSpeed += 0.1; + break; + } + break; + } + case 2: { + maxSpeed += 0.134; + if (wasCollidingVertically && !stuck) { + maxSpeed += 0.06694; + } + if (wasOnIce) { + maxSpeed += 0.08; + } + if (wasNearBed) { + maxSpeed += 0.04; + } + if (nearStair) { + maxSpeed += 0.35; + } + if (wasCollidingVertically && wasOnIce) { + maxSpeed += 0.4; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.55; + } + if (nearSlab) { + maxSpeed += 0.05; + } + if (wasNearTrapdoor) { + maxSpeed += 0.1; + } + if (sinceIceTicks == 0 && nearSlab) { + maxSpeed += 0.005; + } + if (wasNearFence) { + maxSpeed += 0.1; + break; + } + break; + } + case 3: { + maxSpeed += 0.0693; + if (wasCollidingVertically && !stuck) { + maxSpeed += 0.036; + } + if (wasOnIce) { + maxSpeed += 0.045; + } + if (nearStair) { + maxSpeed += 0.35; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.35; + } + if (wasCollidingVertically && wasOnIce) { + maxSpeed += 0.35; + } + if (nearSlab) { + maxSpeed += 0.04; + } + if (wasNearBed) { + maxSpeed += 0.04; + } + if (wasNearFence) { + maxSpeed += 0.1; + } + if (wasNearTrapdoor) { + maxSpeed += 0.1; + break; + } + break; + } + case 4: { + maxSpeed += 0.035; + if (wasCollidingVertically && !stuck) { + maxSpeed += 0.0411; + } + if (wasOnIce) { + maxSpeed += 0.03; + } + if (nearStair) { + maxSpeed += 0.35; + } + if (wasNearTrapdoor) { + maxSpeed += 0.1; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.35; + } + if (wasCollidingVertically && wasOnIce) { + maxSpeed += 0.35; + } + if (nearSlab) { + maxSpeed += 0.04; + break; + } + break; + } + case 5: { + maxSpeed += 0.0205; + if (wasCollidingVertically && !stuck) { + maxSpeed += 0.0431; + } + if (wasOnIce) { + maxSpeed += 0.03; + } + if (nearStair) { + maxSpeed += 0.35; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.35; + } + if (nearSlab) { + maxSpeed += 0.04; + break; + } + break; + } + case 6: { + maxSpeed += 0.009; + if (wasCollidingVertically && !stuck) { + maxSpeed += 0.0527; + } + if (wasOnIce) { + maxSpeed += 0.02; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.35; + } + if (nearSlab) { + maxSpeed += 0.04; + break; + } + break; + } + case 7: { + maxSpeed += 0.005; + if (wasOnIce) { + maxSpeed += 0.02; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.1; + break; + } + break; + } + case 8: { + maxSpeed += 0.003; + if (wasOnIce) { + maxSpeed += 0.02; + } + if (sinceIceTicks == 0 && nearSlab) { + maxSpeed += 0.02; + break; + } + break; + } + case 9: { + maxSpeed += 0.0025; + if (wasOnIce) { + maxSpeed += 0.02; + break; + } + break; + } + } + if (sinceIceTicks == 0) { + if (groundTicks > 2 && groundTicks < 9) { + maxSpeed += 0.09; + } + else if (groundTicks >= 9 && groundTicks < 15) { + maxSpeed += 0.09; + } + else if (groundTicks >= 15) { + maxSpeed += 0.09; + } + } + if (sinceCollidingVerticallyTicks < 20 && groundTicks < 15 && !stuck) { + maxSpeed += 0.1; + } + if (nearSlab) { + maxSpeed += 0.1; + } + if (sinceIceTicks < 30 && groundTicks >= 5 && groundTicks <= 25 && wasCollidingVertically) { + maxSpeed += 0.15; + } + if (this.isExempt(ExemptType.CANCELLED_PLACE)) { + maxSpeed += 0.08; + } + final int sinceNearSlabTicks = this.data.getPositionProcessor().getSinceNearSlabTicks(); + if (sinceNearSlabTicks < 20) { + maxSpeed += 0.075; + } + if (sinceIceTicks < 30 && groundTicks > 8) { + maxSpeed += 0.15; + } + if (depthStrider) { + maxSpeed += 0.1; + } + if (this.isExempt(ExemptType.FARMLAND)) { + maxSpeed += 0.05; + } + if (ServerUtil.isHigherThan1_16() && soulSpeed && this.data.getActionProcessor().getSpeedAmplifier() > 3) { + maxSpeed += 1.25; + } + if (ServerUtil.isHigherThan1_16() && soulSpeed) { + maxSpeed += 0.5; + } + if (wasOnIce && wasNearSlime) { + maxSpeed += 0.35; + } + if (wasNearSlime && wasCollidingVertically) { + maxSpeed += 0.1; + } + final VelocityProcessor.VelocitySnapshot snapshot = this.data.getVelocityProcessor().getSnapshot(); + double velocityXZ = this.data.getVelocityProcessor().getVelocityXZ(); + if (snapshot != null) { + final double velocityX = snapshot.getVelocity().getX(); + final double velocityZ = snapshot.getVelocity().getZ(); + velocityXZ = MathUtil.hypot(velocityX, velocityZ); + } + switch (sinceVelocityTicks) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: { + maxSpeed += velocityXZ + 0.05; + break; + } + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: { + maxSpeed += velocityXZ * 0.75; + break; + } + case 16: + case 17: + case 18: + case 19: + case 20: { + maxSpeed += velocityXZ * 0.6; + break; + } + case 21: + case 22: + case 23: + case 24: + case 25: { + maxSpeed += velocityXZ * 0.5; + break; + } + case 26: + case 27: + case 28: + case 29: + case 30: { + maxSpeed += velocityXZ * 0.35; + break; + } + case 31: + case 32: + case 33: + case 34: + case 35: { + maxSpeed += velocityXZ * 0.25; + break; + } + case 36: + case 37: + case 38: + case 39: + case 40: { + maxSpeed += velocityXZ * 0.1; + break; + } + } + if (this.data.getPositionProcessor().getSinceNearIceTicks() < 40) { + maxSpeed += 0.125; + } + if (this.data.getPositionProcessor().isNearTrapdoor()) { + maxSpeed += 0.125; + } + if (this.data.getPositionProcessor().getSinceAroundSlimeTicks() < 15) { + maxSpeed += 0.6; + } + if (ServerUtil.isHigherThan1_9() && Config.ENTITY_COLLISION_FIX && this.data.getPositionProcessor().getSinceEntityCollisionTicks() < 20) { + maxSpeed += 0.1; + } + if (this.data.getActionProcessor().getSinceIcePlaceTicks() < 40) { + maxSpeed += 0.2; + } + if (this.isExempt(ExemptType.PISTON)) { + maxSpeed += 0.325; + } + if (this.isExempt(ExemptType.CAKE)) { + maxSpeed += 0.1; + } + if (this.isExempt(ExemptType.STAIRS, ExemptType.SLAB)) { + maxSpeed += 0.45; + } + if (this.isExempt(ExemptType.BED)) { + maxSpeed += 0.25; + } + if (this.isExempt(ExemptType.FENCE)) { + maxSpeed += 0.225; + } + if (this.isExempt(ExemptType.BUKKIT_VELOCITY)) { + maxSpeed += velocityXZ * 2.0; + } + if (this.isExempt(ExemptType.SPEED_RAN_OUT)) { + ++maxSpeed; + } + if (this.isExempt(ExemptType.SNOW)) { + maxSpeed += 0.05; + } + if (this.data.getActionProcessor().getSinceRavagerDamageTicks() < 30) { + maxSpeed += 2.0; + } + if (this.data.getActionProcessor().getSinceCrystalDamageTicks() < 5) { + ++maxSpeed; + } + else if (this.data.getActionProcessor().getSinceCrystalDamageTicks() > 5 && this.data.getActionProcessor().getSinceCrystalDamageTicks() < 25) { + maxSpeed += 0.5; + } + if (this.data.getPositionProcessor().isNearPressurePlate()) { + maxSpeed += 0.08; + } + final double difference = deltaXZ - maxSpeed; + final boolean exempt = this.isExempt(ExemptType.FLIGHT, ExemptType.JOINED, ExemptType.CREATIVE, ExemptType.SHULKER, ExemptType.SHULKER_BOX, ExemptType.DOLPHINS_GRACE, ExemptType.TELEPORT, ExemptType.ILLEGAL_BLOCK, ExemptType.GLIDING, ExemptType.CANCELLED_MOVE, ExemptType.RIPTIDE, ExemptType.VEHICLE, ExemptType.BOAT, ExemptType.FISHING_ROD, ExemptType.ELYTRA, ExemptType.CHUNK, ExemptType.DEATH, ExemptType.SLEEPING, ExemptType.ENDER_PEARL, ExemptType.FROZEN, ExemptType.CHORUS_FRUIT, ExemptType.ENTITY_CRAM_FIX, ExemptType.SPECTATOR, ExemptType.WORLD_CHANGE, ExemptType.ATTRIBUTE_MODIFIER, ExemptType.ANVIL); + final boolean invalid = difference > Config.SPEED_D_MIN_DIFFERENCE && groundTicks >= 0; + final int sinceTeleportTicks = this.data.getActionProcessor().getSinceTeleportTicks(); + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER || (difference > 0.5 && difference < 100.0 && !this.isExempt(ExemptType.SERVER_POSITION))) { + this.fail("speed=" + deltaXZ + " max=" + maxSpeed + " diff=" + difference + " ticks=" + groundTicks + " deltaY=" + deltaY + " tp=" + sinceTeleportTicks); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/sprint/SprintA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/sprint/SprintA.java new file mode 100644 index 0000000..69cac5d --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/sprint/SprintA.java @@ -0,0 +1,35 @@ +package me.frep.vulcan.spigot.check.impl.movement.sprint; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Sprint", type = 'A', complexType = "Angle", description = "Invalid sprint direction.") +public class SprintA extends AbstractCheck +{ + public SprintA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting()) { + final float angle = this.data.getRotationProcessor().getMovementAngle(); + final int groundTicks = this.data.getPositionProcessor().getClientGroundTicks(); + final int sprintTicks = this.data.getActionProcessor().getSprintingTicks(); + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final boolean invalid = sprintTicks > 10 && angle > 1.5 && groundTicks > 6 && deltaXZ > 0.25; + final boolean exempt = this.isExempt(ExemptType.RIPTIDE, ExemptType.TELEPORT, ExemptType.WORLD_CHANGE, ExemptType.JOINED, ExemptType.SERVER_POSITION, ExemptType.SWIMMING, ExemptType.LIQUID, ExemptType.ICE, ExemptType.SWIMMING, ExemptType.SERVER_POSITION); + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("angle=" + angle + " ticks=" + sprintTicks); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/step/StepA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/step/StepA.java new file mode 100644 index 0000000..3d1f2ff --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/step/StepA.java @@ -0,0 +1,28 @@ +package me.frep.vulcan.spigot.check.impl.movement.step; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Step", type = 'A', complexType = "Vanilla", description = "Invalid Step height.") +public class StepA extends AbstractCheck +{ + public StepA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting()) { + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final boolean onGround = this.data.getPositionProcessor().isClientOnGround(); + final boolean exempt = this.isExempt(ExemptType.JOINED, ExemptType.TELEPORT, ExemptType.SHULKER_BOX, ExemptType.SPECTATOR, ExemptType.WORLD_CHANGE, ExemptType.RIPTIDE, ExemptType.BOAT, ExemptType.VEHICLE, ExemptType.PISTON, ExemptType.SHULKER, ExemptType.ENDER_PEARL, ExemptType.SLEEPING, ExemptType.BED); + final boolean invalid = onGround && deltaY > 0.6000000238418579; + if (invalid && !exempt) { + this.fail("deltaY=" + deltaY); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/step/StepB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/step/StepB.java new file mode 100644 index 0000000..828fd74 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/step/StepB.java @@ -0,0 +1,61 @@ +package me.frep.vulcan.spigot.check.impl.movement.step; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Step", type = 'B', complexType = "Motion", description = "Invalid Step motion.") +public class StepB extends AbstractCheck +{ + private int ticks; + private int lastAscension; + + public StepB(final PlayerData data) { + super(data); + this.ticks = 0; + this.lastAscension = 0; + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting()) { + if (this.data.getActionProcessor().isCrawling()) { + return; + } + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final int groundTicks = this.data.getPositionProcessor().getClientGroundTicks(); + if (deltaY > 0.2) { + ++this.ticks; + this.lastAscension = this.ticks(); + } + else if ((deltaY < 0.2 && deltaY > 0.0) || groundTicks > 16) { + this.ticks = 0; + } + final boolean bed = this.data.getPositionProcessor().getSinceNearBedTicks() < 30; + final boolean explosion = this.data.getActionProcessor().getSinceExplosionDamageTicks() < 100; + final boolean exempt = this.isExempt(ExemptType.JOINED, ExemptType.TELEPORT, ExemptType.FENCE, ExemptType.STAIRS, ExemptType.FLIGHT, ExemptType.CREATIVE, ExemptType.VELOCITY, ExemptType.COLLIDING_VERTICALLY, ExemptType.TRAPDOOR, ExemptType.SLAB, ExemptType.SLIME, ExemptType.WALL, ExemptType.GLIDING, ExemptType.RIPTIDE, ExemptType.VEHICLE, ExemptType.SEA_PICKLE, ExemptType.TURTLE_EGG, ExemptType.BOAT, ExemptType.SLEEPING, ExemptType.SNOW, ExemptType.ANVIL, ExemptType.POWDER_SNOW, ExemptType.END_ROD, ExemptType.CHAIN, ExemptType.PISTON, ExemptType.JUMP_BOOST, ExemptType.CAULDRON, ExemptType.HOPPER, ExemptType.CANCELLED_PLACE, ExemptType.ENDER_PEARL, ExemptType.SERVER_POSITION_FAST, ExemptType.FULLY_STUCK, ExemptType.ELYTRA, ExemptType.GLIDING, ExemptType.LEVITATION, ExemptType.FISHING_ROD, ExemptType.SWEET_BERRIES, ExemptType.ILLEGAL_BLOCK, ExemptType.GLITCHED_BLOCKS_ABOVE, ExemptType.SHULKER, ExemptType.SHULKER_BOX, ExemptType.CAKE, ExemptType.FLOWER_POT, ExemptType.TURTLE_EGG) || this.data.getPositionProcessor().isNearEnchantmentTable(); + final boolean bell = this.data.getPositionProcessor().isNearBell(); + final boolean lantern = this.data.getPositionProcessor().isNearLantern(); + final boolean amethyst = this.data.getPositionProcessor().isNearAmethyst(); + final boolean reset = this.ticks() - this.lastAscension > 20; + if (exempt || reset || bed || explosion || bell || lantern || amethyst) { + this.resetBuffer(); + this.ticks = 0; + return; + } + if (this.ticks > 3) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + this.ticks + " deltaY=" + deltaY); + } + } + else { + this.decayBuffer(); + } + } + else if (packet.isTeleport()) { + this.ticks = 0; + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/step/StepC.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/step/StepC.java new file mode 100644 index 0000000..b7c5f0c --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/step/StepC.java @@ -0,0 +1,287 @@ +package me.frep.vulcan.spigot.check.impl.movement.step; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Step", type = 'C', complexType = "Motion", description = "Reverse step.") +public class StepC extends AbstractCheck +{ + int nearGroundTicks; + + public StepC(final PlayerData data) { + super(data); + this.nearGroundTicks = 0; + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting() && !this.fuckedPosition()) { + if (this.data.getActionProcessor().getPositionTicksExisted() < 30) { + return; + } + final int airTicks = this.data.getPositionProcessor().getClientAirTicks(); + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + if (this.data.getActionProcessor().getDistanceFromLastBreak() < 1.25 && this.data.getActionProcessor().getDistanceFromLastBreak() > 0.0) { + return; + } + final float fallDistance = this.data.getPlayer().getFallDistance(); + final boolean exempt = this.isExempt(ExemptType.TELEPORT, ExemptType.WORLD_CHANGE, ExemptType.DOOR, ExemptType.DRAGON_DAMAGE, ExemptType.DEATH, ExemptType.JOINED, ExemptType.FLIGHT, ExemptType.CREATIVE, ExemptType.GLIDING, ExemptType.EXPLOSION, ExemptType.CANCELLED_PLACE, ExemptType.ELYTRA, ExemptType.LIQUID, ExemptType.VEHICLE, ExemptType.RIPTIDE, ExemptType.SLEEPING, ExemptType.BLOCK_PLACE, ExemptType.VELOCITY, ExemptType.FAST, ExemptType.GLIDING, ExemptType.BUKKIT_VELOCITY, ExemptType.SLIME, ExemptType.ENDER_PEARL, ExemptType.ANVIL, ExemptType.END_ROD, ExemptType.CHAIN, ExemptType.DRIPSTONE, ExemptType.SERVER_POSITION, ExemptType.PISTON, ExemptType.JUMP_BOOST, ExemptType.CLIMBABLE, ExemptType.SCAFFOLDING) || this.data.getPositionProcessor().isNearAmethyst() || this.data.getPositionProcessor().isNearDripstone() || this.data.getActionProcessor().getSinceCrystalDamageTicks() < 20; + final boolean nearGround = this.data.getPositionProcessor().isNearGround(); + if (nearGround) { + ++this.nearGroundTicks; + } + else { + this.nearGroundTicks = 0; + } + if (!exempt) { + switch (airTicks) { + case 0: { + if (deltaY >= -0.5 || this.nearGroundTicks <= 5) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance + " ng=" + this.nearGroundTicks); + break; + } + break; + } + case 1: { + if (deltaY >= -0.07850000262260437) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + break; + } + break; + } + case 2: { + if (deltaY >= -0.15530000627040863) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + break; + } + break; + } + case 3: { + if (deltaY >= -0.2305999994277954) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + } + } + case 4: { + if (deltaY >= -0.3043999969959259) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + } + } + case 5: { + if (deltaY >= -0.376800000667572) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + } + } + case 6: { + if (deltaY >= -0.44749999046325684) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + } + } + case 7: { + if (deltaY >= -0.5170999765396118) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + } + } + case 8: { + if (deltaY >= -0.5860000252723694) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + } + } + case 9: { + if (deltaY >= -0.6520000100135803) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + } + } + case 10: { + if (deltaY >= -0.7171000242233276) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + } + } + case 11: { + if (deltaY >= -0.7811999917030334) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + } + } + case 12: { + if (deltaY >= -0.843999981880188) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + } + } + case 13: { + if (deltaY >= -0.9054999947547913) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + } + } + case 14: { + if (deltaY >= -0.9657999873161316) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + } + } + case 15: { + if (deltaY >= -1.024899959564209) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + } + } + case 16: { + if (deltaY >= -1.082800030708313) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + } + } + case 17: { + if (deltaY >= -1.1395000219345093) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + } + } + case 18: { + if (deltaY >= -1.195099949836731) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + } + } + case 19: { + if (deltaY >= -1.2496000528335571) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + } + } + case 20: { + if (deltaY >= -1.3029999732971191) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + } + } + case 21: { + if (deltaY >= -1.3559999465942383) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + } + } + case 22: { + if (deltaY >= -1.406999945640564) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + } + } + case 23: { + if (deltaY >= -1.4570000171661377) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + } + } + case 24: { + if (deltaY >= -1.5069999694824219) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + } + } + case 25: { + if (deltaY >= -1.5549999475479126) { + this.decayBuffer(); + break; + } + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + airTicks + " deltaY=" + deltaY + " distance=" + fallDistance); + break; + } + break; + } + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/strafe/StrafeA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/strafe/StrafeA.java new file mode 100644 index 0000000..18fcd5e --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/strafe/StrafeA.java @@ -0,0 +1,54 @@ +package me.frep.vulcan.spigot.check.impl.movement.strafe; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Strafe", type = 'A', complexType = "Air", description = "Moving incorrectly in the air.") +public class StrafeA extends AbstractCheck +{ + private boolean wasSprinting; + + public StrafeA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting() && !this.fuckedPosition()) { + final boolean sprinting = this.data.getActionProcessor().isSprinting(); + final int sinceSprintingTicks = this.data.getActionProcessor().getSinceSprintingTicks(); + final int airTicks = this.data.getPositionProcessor().getClientAirTicks(); + final double lastDeltaX = this.data.getPositionProcessor().getLastDeltaX(); + final double lastDeltaZ = this.data.getPositionProcessor().getLastDeltaZ(); + final double deltaX = this.data.getPositionProcessor().getDeltaX(); + final double deltaZ = this.data.getPositionProcessor().getDeltaZ(); + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double predictedX = lastDeltaX * 0.9100000262260437; + final double predictedZ = lastDeltaZ * 0.9100000262260437; + final double differenceX = deltaX - predictedX; + final double differenceZ = deltaZ - predictedZ; + double difference = MathUtil.hypot(differenceX, differenceZ); + difference /= (this.wasSprinting ? 1.3 : 1.0); + difference -= ((sprinting || sinceSprintingTicks < 2) ? 0.026 : 0.02); + final boolean velocity = this.data.getVelocityProcessor().getTransactionFlyingTicks() < 3; + final boolean piston = this.data.getPositionProcessor().getSinceNearPistonTicks() < 30; + final boolean exempt = this.isExempt(ExemptType.TELEPORT, ExemptType.PARTIALLY_STUCK, ExemptType.BUKKIT_VELOCITY, ExemptType.DEATH, ExemptType.JOINED, ExemptType.WORLD_CHANGE, ExemptType.FLIGHT, ExemptType.FULLY_STUCK, ExemptType.GLIDING, ExemptType.ELYTRA, ExemptType.CREATIVE, ExemptType.SPECTATOR, ExemptType.SOUL_SAND, ExemptType.VEHICLE, ExemptType.ENTITY_COLLISION, ExemptType.DEPTH_STRIDER, ExemptType.FROZEN, ExemptType.LIQUID, ExemptType.DOLPHINS_GRACE, ExemptType.RIPTIDE, ExemptType.SWIMMING, ExemptType.CLIMBABLE, ExemptType.ENDER_PEARL, ExemptType.FIREBALL, ExemptType.CHORUS_FRUIT, ExemptType.BLOCK_BREAK, ExemptType.CANCELLED_MOVE); + final boolean explosion = this.data.getActionProcessor().getSinceExplosionDamageTicks() < 10; + final boolean bowBoost = this.data.getActionProcessor().getSinceBowBoostTicks() < 30; + final boolean invalid = difference > 0.0075 && deltaXZ > 0.25 && airTicks > 3; + if (invalid && !exempt && !piston && !velocity && !explosion && !bowBoost) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("difference=" + difference + " deltaXZ=" + deltaXZ); + } + } + else { + this.decayBuffer(); + } + this.wasSprinting = sprinting; + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/strafe/StrafeB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/strafe/StrafeB.java new file mode 100644 index 0000000..3414e45 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/strafe/StrafeB.java @@ -0,0 +1,38 @@ +package me.frep.vulcan.spigot.check.impl.movement.strafe; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Strafe", type = 'B', complexType = "Ground", description = "Moving incorrectly on the ground.") +public class StrafeB extends AbstractCheck +{ + public StrafeB(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting() && !this.fuckedPosition()) { + final int groundTicks = this.data.getPositionProcessor().getClientGroundTicks(); + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final float moveForward = this.data.getPositionProcessor().getMoveForward(); + final float moveStrafing = this.data.getPositionProcessor().getMoveStrafing(); + final boolean onGround = this.data.getPositionProcessor().isClientOnGround(); + final boolean sprinting = this.data.getActionProcessor().isSprinting(); + final boolean env = onGround && sprinting; + final boolean flag = moveForward < 0.0f || (moveForward == 0.0f && moveStrafing != 0.0f); + final boolean exempt = this.isExempt(ExemptType.GLIDING, ExemptType.ELYTRA, ExemptType.DOLPHINS_GRACE, ExemptType.BUKKIT_VELOCITY, ExemptType.DEPTH_STRIDER, ExemptType.ICE, ExemptType.SLIME, ExemptType.PISTON, ExemptType.SWIMMING, ExemptType.SERVER_POSITION, ExemptType.LIQUID, ExemptType.SOUL_SPEED, ExemptType.WEB, ExemptType.ENTITY_COLLISION, ExemptType.TELEPORT, ExemptType.VELOCITY, ExemptType.SERVER_POSITION); + if (env && flag && groundTicks > 3 && !exempt && deltaXZ > 0.25) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("forward=" + moveForward + " strafe=" + moveStrafing + " deltaXZ=" + deltaXZ); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/vclip/VClipA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/vclip/VClipA.java new file mode 100644 index 0000000..114f831 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/vclip/VClipA.java @@ -0,0 +1,37 @@ +package me.frep.vulcan.spigot.check.impl.movement.vclip; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.value.Values; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "VClip", type = 'A', complexType = "Clip", description = "Large vertical movement.") +public class VClipA extends AbstractCheck +{ + public VClipA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting() && !this.fuckedPosition()) { + if (this.data.getActionProcessor().getTicksExisted() < 30) { + return; + } + final int airTicks = this.data.getPositionProcessor().getClientAirTicks(); + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + if (airTicks < 5 && airTicks > 0) { + final double expected = Values.JUMP_MOTION_DOWN.get(airTicks); + final double difference = Math.abs(deltaY - expected); + final boolean explosion = this.data.getActionProcessor().getSinceExplosionDamageTicks() < 50; + final boolean damage = this.data.getActionProcessor().getSinceDamageTicks() < 20; + final boolean exempt = this.isExempt(ExemptType.VELOCITY, ExemptType.JOINED, ExemptType.TELEPORT, ExemptType.LIQUID, ExemptType.CLIMBABLE, ExemptType.GLIDING, ExemptType.RIPTIDE, ExemptType.COLLIDING_VERTICALLY, ExemptType.HOPPER, ExemptType.SLIME, ExemptType.SCAFFOLDING, ExemptType.BOAT, ExemptType.TRAPDOOR, ExemptType.STAIRS, ExemptType.SHULKER, ExemptType.FLIGHT, ExemptType.CREATIVE, ExemptType.SLAB, ExemptType.ILLEGAL_BLOCK, ExemptType.TELEPORT, ExemptType.FENCE, ExemptType.JUMP_BOOST, ExemptType.HONEY, ExemptType.FISHING_ROD, ExemptType.WEB, ExemptType.FULLY_STUCK, ExemptType.SHULKER_BOX, ExemptType.ELYTRA, ExemptType.VEHICLE, ExemptType.BED, ExemptType.BLOCK_PLACE, ExemptType.SLEEPING, ExemptType.CANCELLED_BREAK, ExemptType.ANVIL, ExemptType.PISTON, ExemptType.TURTLE_EGG, ExemptType.DOOR, ExemptType.DEATH, ExemptType.PARTIALLY_STUCK, ExemptType.WALL, ExemptType.PLACED_WEB, ExemptType.ENDER_PEARL, ExemptType.BUKKIT_VELOCITY, ExemptType.LEVITATION, ExemptType.BUBBLE_COLUMN, ExemptType.FROZEN, ExemptType.BLOCK_BREAK, ExemptType.SWEET_BERRIES, ExemptType.EMPTIED_BUCKET, ExemptType.SERVER_POSITION_FAST, ExemptType.FARMLAND, ExemptType.LENIENT_SCAFFOLDING, ExemptType.ATTACK_DAMAGE, ExemptType.SEAGRASS, ExemptType.DRIPSTONE, ExemptType.WATERLOGGED, ExemptType.CHEST, ExemptType.SOUL_SAND, ExemptType.GLITCHED_BLOCKS_ABOVE, ExemptType.POWDER_SNOW); + if (!explosion && !damage && !exempt && deltaY < 0.0 && difference > 0.75) { + this.fail("deltaY=" + deltaY + " ticks=" + airTicks); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/movement/wallclimb/WallClimbA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/wallclimb/WallClimbA.java new file mode 100644 index 0000000..18bc911 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/movement/wallclimb/WallClimbA.java @@ -0,0 +1,79 @@ +package me.frep.vulcan.spigot.check.impl.movement.wallclimb; + +import java.util.Iterator; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import org.bukkit.Material; +import me.frep.vulcan.spigot.util.BlockUtil; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Wall Climb", type = 'A', complexType = "Spider", description = "Climbing up a wall.") +public class WallClimbA extends AbstractCheck +{ + private int ticks; + + public WallClimbA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition()) { + final double x = Math.abs(this.data.getPositionProcessor().getX() % 1.0); + final double z = Math.abs(this.data.getPositionProcessor().getZ() % 1.0); + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final double diff = Math.abs(deltaY - 0.20000004768371582); + if (diff < 0.001) { + return; + } + if (this.data.getActionProcessor().getDistanceFromLastBreak() < 1.25 && this.data.getActionProcessor().getDistanceFromLastBreak() > 0.0) { + return; + } + final boolean collidingVertically = this.data.getPositionProcessor().isCollidingVertically(); + final boolean againstWall = (x > 0.67 && x < 0.73) || (z > 0.67 && z < 0.73) || (x > 0.27 && x < 0.33) || (z > 0.27 && z < 0.33); + if (againstWall) { + ++this.ticks; + } + else { + this.ticks = 0; + } + Material below; + if (ServerUtil.isHigherThan1_13()) { + below = this.data.getPositionProcessor().getBlockBelowModern(); + } + else { + below = this.data.getPositionProcessor().getBlockBelow(); + } + if (below != null && !BlockUtil.isAir(below)) { + this.ticks = 0; + } + if (this.data.getPositionProcessor().getBlocksAbove() != null && this.data.getPositionProcessor().getBlocksBelow() != null) { + int aboveAir = 0; + int belowAir = 0; + for (final Material material : this.data.getPositionProcessor().getBlocksAbove()) { + if (BlockUtil.isAir(material)) { + ++aboveAir; + } + } + for (final Material material : this.data.getPositionProcessor().getBlocksBelow()) { + if (BlockUtil.isAir(material)) { + ++belowAir; + } + } + final boolean invalid = this.ticks > 5 && deltaY > 0.1 && aboveAir == belowAir; + final boolean exempt = this.isExempt(ExemptType.CLIMBABLE, ExemptType.SCAFFOLDING, ExemptType.JUMP_BOOST, ExemptType.BLOCK_PLACE, ExemptType.FLIGHT, ExemptType.CREATIVE, ExemptType.GLIDING, ExemptType.LEVITATION, ExemptType.VELOCITY, ExemptType.RIPTIDE, ExemptType.CANCELLED_PLACE, ExemptType.NEAR_GROUND, ExemptType.POWDER_SNOW, ExemptType.SLIME, ExemptType.LIQUID, ExemptType.END_ROD, ExemptType.SHULKER, ExemptType.SHULKER_BOX, ExemptType.BUBBLE_COLUMN, ExemptType.WATERLOGGED, ExemptType.EMPTIED_BUCKET, ExemptType.TRAPDOOR); + if (invalid && !exempt && collidingVertically) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaY=" + deltaY + " ticks=" + this.ticks); + } + } + else { + this.decayBuffer(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/airplace/AirPlaceA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/airplace/AirPlaceA.java new file mode 100644 index 0000000..d5b166b --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/airplace/AirPlaceA.java @@ -0,0 +1,34 @@ +package me.frep.vulcan.spigot.check.impl.player.airplace; + +import me.frep.vulcan.spigot.util.BlockUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import org.bukkit.event.block.BlockPlaceEvent; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Air Place", type = 'A', complexType = "Invalid", description = "Invalid block placement.", experimental = true) +public class AirPlaceA extends AbstractCheck +{ + public AirPlaceA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isBlockPlaceEvent()) { + final BlockPlaceEvent event = (BlockPlaceEvent)packet.getRawPacket().getRawNMSPacket(); + final boolean exempt = this.isExempt(ExemptType.SPECTATOR, ExemptType.CANCELLED_PLACE, ExemptType.CREATIVE); + if (event.isCancelled() || exempt) { + return; + } + if (BlockUtil.isSlab(event.getBlock().getType()) || BlockUtil.isSand(event.getBlock().getType()) || BlockUtil.isGravel(event.getBlock().getType()) || BlockUtil.isAnvil(event.getBlock().getType()) || BlockUtil.isPath(event.getBlock().getType()) || BlockUtil.isStripped(event.getBlock().getType()) || BlockUtil.isFarmland(event.getBlock().getType())) { + return; + } + if (event.getBlockAgainst().getX() == event.getBlock().getX() && event.getBlockAgainst().getY() == event.getBlock().getY() && event.getBlockAgainst().getZ() == event.getBlock().getZ() && BlockUtil.isAir(event.getBlock().getLocation().add(0.0, 1.0, 0.0).getBlock().getType()) && BlockUtil.isAir(event.getBlock().getLocation().add(0.0, -1.0, 0.0).getBlock().getType()) && BlockUtil.isAir(event.getBlock().getLocation().add(1.0, 0.0, 0.0).getBlock().getType()) && BlockUtil.isAir(event.getBlock().getLocation().add(-1.0, 0.0, 0.0).getBlock().getType()) && BlockUtil.isAir(event.getBlock().getLocation().add(0.0, 0.0, 1.0).getBlock().getType()) && BlockUtil.isAir(event.getBlock().getLocation().add(0.0, 0.0, -1.0).getBlock().getType())) { + this.fail("block= " + event.getBlock().getType()); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPackets1.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPackets1.java new file mode 100644 index 0000000..90cc04a --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPackets1.java @@ -0,0 +1,47 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import org.bukkit.inventory.ItemStack; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import org.bukkit.enchantments.Enchantment; +import io.github.retrooper.packetevents.packetwrappers.play.in.blockdig.WrappedPacketInBlockDig; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = '1', complexType = "Nuker", description = "Sent too many Start Dig packets.") +public class BadPackets1 extends AbstractCheck +{ + private long lastStart; + + public BadPackets1(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isBlockDig()) { + final WrappedPacketInBlockDig wrapper = this.data.getBlockDigWrapper(); + if (wrapper.getDigType() == WrappedPacketInBlockDig.PlayerDigType.START_DESTROY_BLOCK) { + final long now = System.currentTimeMillis(); + final long delay = now - this.lastStart; + final ItemStack tool = this.data.getPlayer().getItemInHand(); + if (tool.containsEnchantment(Enchantment.DIG_SPEED) && tool.getEnchantmentLevel(Enchantment.DIG_SPEED) > 5) { + return; + } + final boolean exempt = this.isExempt(ExemptType.FAST, ExemptType.SWIMMING, ExemptType.LIQUID, ExemptType.KELP); + final boolean invalid = delay < 3L; + final boolean netherrack = this.data.getActionProcessor().getSinceNetherrackBreakTicks() < 20; + if (invalid && !exempt && !netherrack) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("delay=" + delay); + } + } + else { + this.decayBuffer(); + } + this.lastStart = System.currentTimeMillis(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPackets2.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPackets2.java new file mode 100644 index 0000000..1355ca8 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPackets2.java @@ -0,0 +1,46 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import org.bukkit.inventory.ItemStack; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import org.bukkit.enchantments.Enchantment; +import io.github.retrooper.packetevents.packetwrappers.play.in.blockdig.WrappedPacketInBlockDig; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = '2', complexType = "Nuker", description = "Sent too many Stop Dig packets.") +public class BadPackets2 extends AbstractCheck +{ + private long lastStop; + + public BadPackets2(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isBlockDig()) { + final WrappedPacketInBlockDig wrapper = this.data.getBlockDigWrapper(); + if (wrapper.getDigType() == WrappedPacketInBlockDig.PlayerDigType.STOP_DESTROY_BLOCK) { + final long now = System.currentTimeMillis(); + final long delay = now - this.lastStop; + final ItemStack tool = this.data.getPlayer().getItemInHand(); + if (tool.containsEnchantment(Enchantment.DIG_SPEED) && tool.getEnchantmentLevel(Enchantment.DIG_SPEED) > 5) { + return; + } + final boolean exempt = this.isExempt(ExemptType.FAST); + final boolean invalid = delay < 3L; + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("delay=" + delay); + } + } + else { + this.decayBuffer(); + } + this.lastStop = System.currentTimeMillis(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPackets4.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPackets4.java new file mode 100644 index 0000000..30958fb --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPackets4.java @@ -0,0 +1,42 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import me.frep.vulcan.spigot.util.PlayerUtil; +import io.github.retrooper.packetevents.packetwrappers.play.in.entityaction.WrappedPacketInEntityAction; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = '4', complexType = "Elytra", description = "Sending Elytra packets without an Elytra.") +public class BadPackets4 extends AbstractCheck +{ + public BadPackets4(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isEntityAction()) { + final WrappedPacketInEntityAction wrapper = this.data.getEntityActionWrapper(); + final boolean exempt = this.isExempt(ExemptType.FLIGHT); + if (!exempt) { + if (wrapper.getAction() == WrappedPacketInEntityAction.PlayerAction.START_FALL_FLYING) { + final boolean elytra = this.data.getActionProcessor().isWearingElytra(); + final boolean version = PlayerUtil.isHigherThan1_9(this.data.getPlayer()); + if (!elytra && version) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("elytra=" + elytra + " action=" + wrapper.getAction()); + } + } + else { + this.decayBuffer(); + } + } + } + } + else if (packet.isFlying()) { + this.decayBuffer(); + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPackets5.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPackets5.java new file mode 100644 index 0000000..904fda5 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPackets5.java @@ -0,0 +1,34 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import java.util.Optional; +import io.github.retrooper.packetevents.utils.vector.Vector3f; +import io.github.retrooper.packetevents.packetwrappers.play.in.blockplace.WrappedPacketInBlockPlace; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = '5', complexType = "Elytra", description = "Invalid Block place.") +public class BadPackets5 extends AbstractCheck +{ + public BadPackets5(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isBlockPlace()) { + final WrappedPacketInBlockPlace wrapper = new WrappedPacketInBlockPlace(packet.getRawPacket()); + final Optional optional = wrapper.getCursorPosition(); + if (optional.isPresent()) { + final Vector3f cursorPosition = optional.get(); + final float x = cursorPosition.getX(); + final float y = cursorPosition.getY(); + final float z = cursorPosition.getZ(); + if (x > 1.0f || y > 1.0f || z > 1.0f || x < 0.0f || y < 0.0f || z < 0.0f) { + this.fail("x=" + x + " y=" + y + " z=" + z); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsA.java new file mode 100644 index 0000000..764efe8 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsA.java @@ -0,0 +1,55 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import java.util.Optional; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import io.github.retrooper.packetevents.packetwrappers.play.in.abilities.WrappedPacketInAbilities; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = 'A', complexType = "Abilities", description = "Spoofed abilities packets.") +public class BadPacketsA extends AbstractCheck +{ + private int lastServerAbilities; + + public BadPacketsA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isAbilities()) { + if (this.data.getPositionProcessor().isFuckedPosition()) { + return; + } + final WrappedPacketInAbilities wrapper = new WrappedPacketInAbilities(packet.getRawPacket()); + final boolean exempt = this.isExempt(ExemptType.DEATH); + if (!this.data.getPlayer().getAllowFlight() && !exempt && this.ticks() - this.lastServerAbilities >= 200) { + if (!this.data.getPositionProcessor().isAllowFlight()) { + final Optional flightAllowed = wrapper.isFlightAllowed(); + if (ServerUtil.isHigherThan1_9()) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("flying=" + wrapper.isFlying()); + } + else { + this.decayBuffer(); + } + } + else if (flightAllowed.isPresent() && flightAllowed.get()) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("flightAllowed=" + wrapper.isFlightAllowed()); + } + else { + this.decayBuffer(); + } + } + } + } + } + else if (packet.isAbilitiesOut()) { + this.lastServerAbilities = this.ticks(); + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsB.java new file mode 100644 index 0000000..86e256b --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsB.java @@ -0,0 +1,36 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import io.github.retrooper.packetevents.packetwrappers.play.in.flying.WrappedPacketInFlying; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = 'B', complexType = "Sequence", description = "More than 20 flying packets in a row.") +public class BadPacketsB extends AbstractCheck +{ + private int streak; + + public BadPacketsB(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isFlying()) { + final WrappedPacketInFlying wrapper = this.data.getFlyingWrapper(); + if (wrapper.isPosition() || this.data.getPlayer().isInsideVehicle()) { + this.streak = 0; + return; + } + final boolean exempt = this.isExempt(ExemptType.SERVER_VERSION, ExemptType.CLIENT_VERSION); + if (++this.streak > 20 && !exempt) { + this.fail("streak=" + this.streak); + } + } + else if (packet.isSteerVehicle()) { + this.streak = 0; + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsC.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsC.java new file mode 100644 index 0000000..804b3c0 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsC.java @@ -0,0 +1,24 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = 'C', complexType = "Pitch", description = "Impossible pitch.") +public class BadPacketsC extends AbstractCheck +{ + public BadPacketsC(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isRotation()) { + final float pitch = this.data.getRotationProcessor().getPitch(); + if (Math.abs(pitch) > 90.0f) { + this.fail("pitch=" + pitch); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsD.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsD.java new file mode 100644 index 0000000..431e0e3 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsD.java @@ -0,0 +1,45 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import org.bukkit.GameRule; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import io.github.retrooper.packetevents.packetwrappers.play.in.clientcommand.WrappedPacketInClientCommand; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = 'D', complexType = "Respawn", description = "Spoofed Respawn packet.") +public class BadPacketsD extends AbstractCheck +{ + public BadPacketsD(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isClientCommand()) { + final WrappedPacketInClientCommand wrapper = new WrappedPacketInClientCommand(packet.getRawPacket()); + final boolean exempt = this.isExempt(ExemptType.DEATH, ExemptType.WORLD_CHANGE, ExemptType.TELEPORT, ExemptType.JOINED); + if (wrapper.getClientCommand() == WrappedPacketInClientCommand.ClientCommand.PERFORM_RESPAWN) { + if (!exempt) { + final double health = this.data.getPlayer().getHealth(); + if (ServerUtil.isHigherThan1_16() && (boolean)this.data.getPlayer().getWorld().getGameRuleValue(GameRule.DO_IMMEDIATE_RESPAWN)) { + return; + } + if (health > 4.0) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("health=" + health); + } + } + else { + this.decayBuffer(); + } + } + } + } + else if (packet.isFlying()) { + this.decayBuffer(); + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsE.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsE.java new file mode 100644 index 0000000..a79e1c3 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsE.java @@ -0,0 +1,27 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import io.github.retrooper.packetevents.packetwrappers.play.in.useentity.WrappedPacketInUseEntity; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = 'E', complexType = "Interact", description = "Interacted with themselves.") +public class BadPacketsE extends AbstractCheck +{ + public BadPacketsE(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isUseEntity()) { + final WrappedPacketInUseEntity wrapper = this.data.getUseEntityWrapper(); + final boolean exempt = this.isExempt(ExemptType.SPECTATOR); + if (wrapper.getEntityId() == this.data.getPlayer().getEntityId() && !exempt) { + this.fail(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsF.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsF.java new file mode 100644 index 0000000..2c840c0 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsF.java @@ -0,0 +1,28 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import io.github.retrooper.packetevents.packetwrappers.play.in.steervehicle.WrappedPacketInSteerVehicle; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = 'F', complexType = "Steer Vehicle", description = "Invalid Steer Vehicle packet.") +public class BadPacketsF extends AbstractCheck +{ + public BadPacketsF(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isSteerVehicle()) { + final WrappedPacketInSteerVehicle wrapper = new WrappedPacketInSteerVehicle(packet.getRawPacket()); + final float forwardValue = wrapper.getForwardValue(); + final float sideValue = wrapper.getSideValue(); + final boolean invalid = Math.abs(forwardValue) > 0.98f || Math.abs(sideValue) > 0.98f; + if (invalid) { + this.fail("forward=" + forwardValue + " side=" + sideValue); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsG.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsG.java new file mode 100644 index 0000000..6fa9f69 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsG.java @@ -0,0 +1,35 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import io.github.retrooper.packetevents.packetwrappers.play.in.helditemslot.WrappedPacketInHeldItemSlot; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = 'G', complexType = "Hotbar", description = "Invalid HeldItemSlot packet.") +public class BadPacketsG extends AbstractCheck +{ + private int lastSlot; + private int lastOutbound; + + public BadPacketsG(final PlayerData data) { + super(data); + this.lastSlot = -1; + } + + @Override + public void handle(final Packet packet) { + if (packet.isHeldItemSlot()) { + final WrappedPacketInHeldItemSlot wrapper = this.data.getHeldItemSlotWrapper(); + final int slot = wrapper.getCurrentSelectedSlot(); + final boolean outbound = this.ticks() - this.lastOutbound < 100; + if (slot == this.lastSlot && !outbound) { + this.fail("slot=" + slot + " lastSlot=" + this.lastSlot); + } + this.lastSlot = slot; + } + else if (packet.isHeldItemSlotOut()) { + this.lastOutbound = this.ticks(); + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsH.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsH.java new file mode 100644 index 0000000..2d02d90 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsH.java @@ -0,0 +1,39 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import io.github.retrooper.packetevents.packetwrappers.play.in.useentity.WrappedPacketInUseEntity; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = 'H', complexType = "Packet Order", description = "Invalid attack packet order.") +public class BadPacketsH extends AbstractCheck +{ + private boolean swung; + + public BadPacketsH(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isUseEntity()) { + final WrappedPacketInUseEntity wrapper = this.data.getUseEntityWrapper(); + final boolean exempt = this.isExempt(ExemptType.SERVER_VERSION, ExemptType.CLIENT_VERSION, ExemptType.FAST); + if (wrapper.getAction() == WrappedPacketInUseEntity.EntityUseAction.ATTACK) { + if (!exempt) { + if (!this.swung) { + this.fail("swung=" + this.swung); + } + } + } + } + else if (packet.isArmAnimation()) { + this.swung = true; + } + else if (packet.isFlying()) { + this.swung = false; + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsI.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsI.java new file mode 100644 index 0000000..a9eab60 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsI.java @@ -0,0 +1,28 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = 'I', complexType = "Entity Action", description = "Sent EntityAction while attacking.") +public class BadPacketsI extends AbstractCheck +{ + public BadPacketsI(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isUseEntity()) { + final boolean invalid = this.data.getActionProcessor().isSendingAction(); + final boolean exempt = this.isExempt(ExemptType.SERVER_VERSION, ExemptType.CLIENT_VERSION, ExemptType.FAST, ExemptType.SPECTATOR, ExemptType.DEATH); + if (invalid) { + if (!exempt) { + this.fail(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsJ.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsJ.java new file mode 100644 index 0000000..36acc16 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsJ.java @@ -0,0 +1,28 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = 'J', complexType = "Held Item Slot", description = "Sent HeldItemSlot while placing.") +public class BadPacketsJ extends AbstractCheck +{ + public BadPacketsJ(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isHeldItemSlot()) { + final boolean placing = this.data.getActionProcessor().isPlacing(); + final boolean exempt = this.isExempt(ExemptType.CLIENT_VERSION, ExemptType.SERVER_VERSION, ExemptType.CREATIVE, ExemptType.SPECTATOR); + if (!exempt) { + if (placing) { + this.fail(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsK.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsK.java new file mode 100644 index 0000000..c7bd280 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsK.java @@ -0,0 +1,40 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import io.github.retrooper.packetevents.packetwrappers.play.in.entityaction.WrappedPacketInEntityAction; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = 'K', complexType = "Sneak", description = "Sending EntityAction packets too quickly") +public class BadPacketsK extends AbstractCheck +{ + private long lastSneak; + + public BadPacketsK(final PlayerData data) { + super(data); + this.lastSneak = -1L; + } + + @Override + public void handle(final Packet packet) { + if (packet.isEntityAction()) { + final WrappedPacketInEntityAction wrapper = this.data.getEntityActionWrapper(); + if (wrapper.getAction() == WrappedPacketInEntityAction.PlayerAction.START_SNEAKING) { + final long now = System.currentTimeMillis(); + final long delay = now - this.lastSneak; + final boolean exempt = this.isExempt(ExemptType.FAST); + if (delay < 90L && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("delay=" + delay); + } + } + else { + this.decayBuffer(); + } + this.lastSneak = now; + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsM.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsM.java new file mode 100644 index 0000000..b759bc8 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsM.java @@ -0,0 +1,48 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = 'M', complexType = "Post BlockPlace", description = "Post BlockPlace packets.") +public class BadPacketsM extends AbstractCheck +{ + private long lastFlying; + private boolean sent; + + public BadPacketsM(final PlayerData data) { + super(data); + this.lastFlying = 0L; + this.sent = false; + } + + @Override + public void handle(final Packet packet) { + if (packet.isFlying()) { + final long delay = System.currentTimeMillis() - this.lastFlying; + final boolean exempt = this.isExempt(ExemptType.CREATIVE, ExemptType.SPECTATOR, ExemptType.WEB, ExemptType.LIQUID, ExemptType.EMPTIED_BUCKET); + final boolean bucket = this.data.getActionProcessor().getSinceStupidBucketEmptyTicks() < 50 || this.data.getPlayer().getItemInHand().getType().toString().contains("BUCKET") || (ServerUtil.isHigherThan1_9() && this.data.getPlayer().getInventory().getItemInOffHand().getType().toString().contains("BUCKET")); + if (this.sent && !exempt && !bucket) { + if (delay > 40L && delay < 100L) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("delay=" + delay); + } + } + else { + this.decayBuffer(); + } + this.sent = false; + } + this.lastFlying = System.currentTimeMillis(); + } + else if (packet.isBlockPlace()) { + final long delay = System.currentTimeMillis() - this.lastFlying; + if (delay < 10L) { + this.sent = true; + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsN.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsN.java new file mode 100644 index 0000000..92f9f22 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsN.java @@ -0,0 +1,44 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = 'N', complexType = "Post BlockDig", description = "Post BlockDig packets.") +public class BadPacketsN extends AbstractCheck +{ + private long lastFlying; + private boolean sent; + + public BadPacketsN(final PlayerData data) { + super(data); + this.lastFlying = 0L; + this.sent = false; + } + + @Override + public void handle(final Packet packet) { + if (packet.isFlying()) { + final long delay = System.currentTimeMillis() - this.lastFlying; + if (this.sent) { + if (delay > 40L && delay < 100L) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail(); + } + } + else { + this.decayBuffer(); + } + this.sent = false; + } + this.lastFlying = System.currentTimeMillis(); + } + else if (packet.isBlockDig()) { + final long delay = System.currentTimeMillis() - this.lastFlying; + if (delay < 10L) { + this.sent = true; + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsO.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsO.java new file mode 100644 index 0000000..0561a1f --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsO.java @@ -0,0 +1,26 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import io.github.retrooper.packetevents.packetwrappers.play.in.helditemslot.WrappedPacketInHeldItemSlot; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = 'O', description = "Negative HeldItemSlot packet.") +public class BadPacketsO extends AbstractCheck +{ + public BadPacketsO(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isHeldItemSlot()) { + final WrappedPacketInHeldItemSlot wrapper = this.data.getHeldItemSlotWrapper(); + final int slot = wrapper.getCurrentSelectedSlot(); + if (slot < 0) { + this.fail("slot=" + slot); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsP.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsP.java new file mode 100644 index 0000000..469af45 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsP.java @@ -0,0 +1,49 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = 'P', complexType = "Post Entity Action", description = "Post EntityAction packets.") +public class BadPacketsP extends AbstractCheck +{ + private long lastFlying; + private boolean sent; + + public BadPacketsP(final PlayerData data) { + super(data); + this.lastFlying = 0L; + this.sent = false; + } + + @Override + public void handle(final Packet packet) { + if (packet.isFlying()) { + final long delay = System.currentTimeMillis() - this.lastFlying; + if (ServerUtil.isHigherThan1_9() || this.isExempt(ExemptType.CREATIVE, ExemptType.SPECTATOR)) { + return; + } + if (this.sent) { + if (delay > 40L && delay < 100L) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail(); + } + } + else { + this.decayBuffer(); + } + this.sent = false; + } + this.lastFlying = System.currentTimeMillis(); + } + else if (packet.isEntityAction()) { + final long delay = System.currentTimeMillis() - this.lastFlying; + if (delay < 10L) { + this.sent = true; + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsQ.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsQ.java new file mode 100644 index 0000000..1579504 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsQ.java @@ -0,0 +1,26 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import io.github.retrooper.packetevents.packetwrappers.play.in.helditemslot.WrappedPacketInHeldItemSlot; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = 'Q', complexType = "Hotbar", description = "Too big HeldItemSlot packet.") +public class BadPacketsQ extends AbstractCheck +{ + public BadPacketsQ(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isHeldItemSlot()) { + final WrappedPacketInHeldItemSlot wrapper = this.data.getHeldItemSlotWrapper(); + final int slot = wrapper.getCurrentSelectedSlot(); + if (slot > 8) { + this.fail("slot=" + slot); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsR.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsR.java new file mode 100644 index 0000000..ef7d9f9 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsR.java @@ -0,0 +1,46 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = 'R', complexType = "Post HeldItemSlot", experimental = false, description = "Post HeldItemSlot packets.") +public class BadPacketsR extends AbstractCheck +{ + private long lastFlying; + private boolean sent; + + public BadPacketsR(final PlayerData data) { + super(data); + this.lastFlying = 0L; + this.sent = false; + } + + @Override + public void handle(final Packet packet) { + if (packet.isFlying()) { + final long delay = System.currentTimeMillis() - this.lastFlying; + final boolean exempt = this.isExempt(ExemptType.CREATIVE, ExemptType.SPECTATOR); + if (this.sent && !exempt) { + if (delay > 40L && delay < 100L) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("delay=" + delay); + } + } + else { + this.decayBuffer(); + } + this.sent = false; + } + this.lastFlying = System.currentTimeMillis(); + } + else if (packet.isHeldItemSlot()) { + final long delay = System.currentTimeMillis() - this.lastFlying; + if (delay < 10L) { + this.sent = true; + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsT.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsT.java new file mode 100644 index 0000000..06ac638 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsT.java @@ -0,0 +1,30 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import io.github.retrooper.packetevents.packetwrappers.play.in.keepalive.WrappedPacketInKeepAlive; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = 'T', complexType = "Keep Alive", experimental = false, description = "Invalid KeepAlive packets.") +public class BadPacketsT extends AbstractCheck +{ + private long lastId; + + public BadPacketsT(final PlayerData data) { + super(data); + this.lastId = -1L; + } + + @Override + public void handle(final Packet packet) { + if (packet.isKeepAlive()) { + final WrappedPacketInKeepAlive wrapper = new WrappedPacketInKeepAlive(packet.getRawPacket()); + final long id = wrapper.getId(); + if (id == this.lastId || id == 0L) { + this.fail("id=" + id + " lastId=" + this.lastId); + } + this.lastId = id; + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsV.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsV.java new file mode 100644 index 0000000..c503fe2 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsV.java @@ -0,0 +1,51 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import org.bukkit.plugin.Plugin; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.Bukkit; +import me.frep.vulcan.spigot.config.Config; +import org.bukkit.entity.Player; +import org.bukkit.entity.ArmorStand; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = 'V', complexType = "Null Vehicle", description = "Spoofed SteerVehicle packets.") +public class BadPacketsV extends AbstractCheck +{ + public BadPacketsV(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isSteerVehicle()) { + if (this.data.getConnectionProcessor().getTransactionPing() > 1500L) { + return; + } + final boolean empty = this.data.getPositionProcessor().getNearbyEntities() != null && this.data.getPositionProcessor().getNearbyEntities().isEmpty(); + final boolean invalid = this.data.getPlayer().getVehicle() == null; + final boolean exempt = this.isExempt(ExemptType.STAIRS, ExemptType.SLAB); + final boolean armorStand = ServerUtil.isHigherThan1_8() && this.data.getPlayer().getVehicle() != null && this.data.getPlayer().getVehicle() instanceof ArmorStand; + final boolean sitting = this.data.getActionProcessor().isSitting(); + final boolean player = this.data.getPlayer().getVehicle() != null && this.data.getPlayer().getVehicle() instanceof Player; + if (invalid && empty && !armorStand && !exempt && !player && !sitting) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("vehicle=" + this.data.getPlayer().getVehicle() + " entities=" + this.data.getPositionProcessor().getNearbyEntities()); + if (Config.BAD_PACKETS_V_KICKOUT) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().leaveVehicle()); + } + } + } + else { + this.decayBuffer(); + } + } + else if (packet.isFlying()) { + this.decreaseBufferBy(0.045); + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsW.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsW.java new file mode 100644 index 0000000..4f26855 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsW.java @@ -0,0 +1,45 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = 'W', complexType = "Post WindowClick", experimental = false, description = "Post WindowClick packets.") +public class BadPacketsW extends AbstractCheck +{ + private long lastFlying; + private boolean sent; + + public BadPacketsW(final PlayerData data) { + super(data); + this.lastFlying = 0L; + this.sent = false; + } + + @Override + public void handle(final Packet packet) { + if (packet.isFlying()) { + final long delay = System.currentTimeMillis() - this.lastFlying; + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + if (this.sent) { + if (delay > 40L && delay < 100L && deltaXZ > 0.1) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail(); + } + } + else { + this.decayBuffer(); + } + this.sent = false; + } + this.lastFlying = System.currentTimeMillis(); + } + else if (packet.isWindowClick()) { + final long delay = System.currentTimeMillis() - this.lastFlying; + if (delay < 10L) { + this.sent = true; + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsX.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsX.java new file mode 100644 index 0000000..c2b60c2 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsX.java @@ -0,0 +1,48 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = 'X', complexType = "Post ArmAnimation", experimental = false, description = "Post ArmAnimation packets.") +public class BadPacketsX extends AbstractCheck +{ + private long lastFlying; + private boolean sent; + + public BadPacketsX(final PlayerData data) { + super(data); + this.lastFlying = 0L; + this.sent = false; + } + + @Override + public void handle(final Packet packet) { + if (packet.isFlying()) { + final long delay = System.currentTimeMillis() - this.lastFlying; + if (this.isExempt(ExemptType.CLIENT_VERSION, ExemptType.SERVER_VERSION)) { + return; + } + if (this.sent) { + if (delay > 40L && delay < 100L) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail(); + } + } + else { + this.decayBuffer(); + } + this.sent = false; + } + this.lastFlying = System.currentTimeMillis(); + } + else if (packet.isArmAnimation()) { + final long delay = System.currentTimeMillis() - this.lastFlying; + if (delay < 10L) { + this.sent = true; + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsY.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsY.java new file mode 100644 index 0000000..4768f12 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsY.java @@ -0,0 +1,26 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = 'Y', complexType = "Invalid Position", description = "NaN X/Y/Z values.") +public class BadPacketsY extends AbstractCheck +{ + public BadPacketsY(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition()) { + final double x = this.data.getPositionProcessor().getX(); + final double y = this.data.getPositionProcessor().getY(); + final double z = this.data.getPositionProcessor().getZ(); + if (Double.isNaN(x) || Double.isNaN(y) || Double.isNaN(z) || x >= 2.147483647E9 || y >= 2.147483647E9 || z >= 2.147483647E9) { + this.fail("x=" + x + " y=" + y + " z=" + z); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsZ.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsZ.java new file mode 100644 index 0000000..e418a18 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/badpackets/BadPacketsZ.java @@ -0,0 +1,29 @@ +package me.frep.vulcan.spigot.check.impl.player.badpackets; + +import org.bukkit.GameMode; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Bad Packets", type = 'Z', complexType = "Spectate", description = "Invalid Spectate Packets.") +public class BadPacketsZ extends AbstractCheck +{ + public BadPacketsZ(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isSpectate()) { + if (ServerUtil.isLowerThan1_8()) { + return; + } + final boolean invalid = this.data.getPlayer().getGameMode() != GameMode.SPECTATOR && this.data.getActionProcessor().getGameMode() != GameMode.SPECTATOR; + if (invalid) { + this.fail(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/baritone/BaritoneA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/baritone/BaritoneA.java new file mode 100644 index 0000000..a54f79d --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/baritone/BaritoneA.java @@ -0,0 +1,41 @@ +package me.frep.vulcan.spigot.check.impl.player.baritone; + +import io.github.retrooper.packetevents.packetwrappers.play.in.blockdig.WrappedPacketInBlockDig; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Baritone", type = 'A', complexType = "Rotations", description = "Checks for Baritone like rotations.") +public class BaritoneA extends AbstractCheck +{ + private int breakTicks; + + public BaritoneA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isRotation() && ++this.breakTicks < 10) { + final float deltaYaw = this.data.getRotationProcessor().getDeltaYaw(); + final float deltaPitch = this.data.getRotationProcessor().getDeltaPitch(); + final boolean cinematic = this.data.getRotationProcessor().isCinematic(); + final boolean invalid = deltaYaw < 0.005 && deltaPitch < 0.005 && deltaYaw > 0.0 && deltaPitch > 0.0 && !cinematic; + if (invalid) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaYaw=" + deltaYaw + " deltaPitch=" + deltaPitch); + } + } + else { + this.decayBuffer(); + } + } + else if (packet.isBlockDig()) { + final WrappedPacketInBlockDig wrapper = this.data.getBlockDigWrapper(); + if (wrapper.getDigType() == WrappedPacketInBlockDig.PlayerDigType.STOP_DESTROY_BLOCK) { + this.breakTicks = 0; + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/baritone/BaritoneB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/baritone/BaritoneB.java new file mode 100644 index 0000000..4224e8e --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/baritone/BaritoneB.java @@ -0,0 +1,41 @@ +package me.frep.vulcan.spigot.check.impl.player.baritone; + +import io.github.retrooper.packetevents.packetwrappers.play.in.blockdig.WrappedPacketInBlockDig; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Baritone", type = 'B', complexType = "Large Rotation", description = "Checks for Baritone like rotations.") +public class BaritoneB extends AbstractCheck +{ + private int breakTicks; + + public BaritoneB(final PlayerData data) { + super(data); + this.breakTicks = 100; + } + + @Override + public void handle(final Packet packet) { + if (packet.isRotation() && ++this.breakTicks < 5) { + final float deltaYaw = this.data.getRotationProcessor().getDeltaYaw(); + final float deltaPitch = this.data.getRotationProcessor().getDeltaPitch(); + final float pitch = this.data.getRotationProcessor().getPitch(); + if (deltaYaw > 95.0f && deltaPitch < 0.15 && Math.abs(pitch) < 70.0f) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaPitch=" + deltaPitch + " deltaYaw=" + deltaYaw); + } + } + else { + this.decayBuffer(); + } + } + else if (packet.isBlockDig()) { + final WrappedPacketInBlockDig wrapper = this.data.getBlockDigWrapper(); + if (wrapper.getDigType() == WrappedPacketInBlockDig.PlayerDigType.STOP_DESTROY_BLOCK) { + this.breakTicks = 0; + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/fastbreak/FastBreakA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/fastbreak/FastBreakA.java new file mode 100644 index 0000000..096c954 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/fastbreak/FastBreakA.java @@ -0,0 +1,58 @@ +package me.frep.vulcan.spigot.check.impl.player.fastbreak; + +import org.bukkit.block.Block; +import me.frep.vulcan.spigot.config.Config; +import org.bukkit.enchantments.Enchantment; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import org.bukkit.event.block.BlockBreakEvent; +import me.frep.vulcan.spigot.util.BreakUtils; +import me.frep.vulcan.spigot.util.BlockUtil; +import org.bukkit.Material; +import org.bukkit.GameMode; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Fast Break", type = 'A', complexType = "Delay", description = "Breaking blocks too quickly.") +public class FastBreakA extends AbstractCheck +{ + private long time; + + public FastBreakA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isInteractEvent()) { + final PlayerInteractEvent event = (PlayerInteractEvent)packet.getRawPacket().getRawNMSPacket(); + if (event.getAction() != Action.LEFT_CLICK_BLOCK || event.isCancelled() || event.getPlayer().getGameMode() != GameMode.SURVIVAL) { + return; + } + final Block block = event.getClickedBlock(); + if (block == null || block.getType() == Material.AIR || block.getType().toString().contains("DOOR") || BlockUtil.isTrapdoor(block.getType()) || block.getType().toString().contains("CONCRETE") || block.getType().toString().contains("TRAP") || block.getType().toString().contains("INFESTED") || BlockUtil.isDoor(block.getType()) || block.getType().toString().equals("FIRE") || block.getType().toString().contains("MUSHROOM") || block.getType().toString().contains("NOTEBLOCK")) { + return; + } + this.time = System.currentTimeMillis() + BreakUtils.getDigTime(block, event.getPlayer()); + } + else if (packet.isBlockBreakEvent()) { + final BlockBreakEvent event2 = (BlockBreakEvent)packet.getRawPacket().getRawNMSPacket(); + final Block block = event2.getBlock(); + if (event2.getPlayer().getGameMode() != GameMode.SURVIVAL || this.data.getActionProcessor().isBerserking() || BlockUtil.isAmethyst(event2.getBlock().getType()) || this.isExempt(ExemptType.VEHICLE) || event2.getBlock().getType().toString().contains("INFESTED") || this.data.getPlayer().getItemInHand().getEnchantmentLevel(Enchantment.DIG_SPEED) > 5 || this.data.getActionProcessor().isHasConduitsPower() || event2.isCancelled() || BlockUtil.isShulkerBox(event2.getBlock().getType()) || BlockUtil.isDeepSlate(event2.getBlock().getType()) || BlockUtil.isAir(event2.getBlock().getType()) || BlockUtil.isPiston(event2.getBlock().getType()) || block.getType().toString().contains("FIRE") || block.getType().toString().contains("DOOR") || BlockUtil.isTrapdoor(block.getType()) || block.getType().toString().contains("CONCRETE") || block.getType().toString().contains("MUSHROOM") || block.getType().toString().contains("NOTEBLOCK") || block.getType().toString().contains("TRAP") || block.getType().toString().contains("INFESTED") || BlockUtil.isDoor(block.getType()) || block.getType().toString().equals("FIRE")) { + return; + } + final double difference = (double)(System.currentTimeMillis() - this.time); + if (difference < Config.FASTBREAK_A_MIN_DIFFERENCE) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("block=" + event2.getBlock().getType() + " diff=" + difference + " tool=" + this.data.getPlayer().getItemInHand().getType()); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/fastplace/FastPlaceA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/fastplace/FastPlaceA.java new file mode 100644 index 0000000..64cb3dc --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/fastplace/FastPlaceA.java @@ -0,0 +1,51 @@ +package me.frep.vulcan.spigot.check.impl.player.fastplace; + +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.util.BlockUtil; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import org.bukkit.event.block.BlockPlaceEvent; +import me.frep.vulcan.spigot.packet.Packet; +import java.util.HashMap; +import me.frep.vulcan.spigot.data.PlayerData; +import java.util.Map; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Fast Place", type = 'A', complexType = "Delay", description = "Placing blocks too quickly.") +public class FastPlaceA extends AbstractCheck +{ + private final Map placed; + private int blocksPlaced; + + public FastPlaceA(final PlayerData data) { + super(data); + this.placed = new HashMap(); + } + + @Override + public void handle(final Packet packet) { + if (packet.isBlockPlaceEvent()) { + final BlockPlaceEvent event = (BlockPlaceEvent)packet.getRawPacket().getRawNMSPacket(); + final boolean exempt = this.isExempt(ExemptType.CANCELLED_BREAK, ExemptType.VEHICLE) || event.isCancelled(); + if (this.data.getPlayer().getItemInHand().getType().toString().contains("HOE")) { + return; + } + if (ServerUtil.isHigherThan1_9() && this.data.getPlayer().getInventory().getItemInOffHand().getType().toString().contains("HOE")) { + return; + } + if (exempt || BlockUtil.isScaffolding(event.getBlock().getType())) { + return; + } + ++this.blocksPlaced; + this.placed.put(this.blocksPlaced, System.currentTimeMillis()); + if (System.currentTimeMillis() - this.placed.get(1) > 1000L) { + if (this.placed.size() > Config.FASTPLACE_A_MAX_BLOCKS) { + this.fail("amount=" + this.placed.size()); + } + this.placed.clear(); + this.blocksPlaced = 0; + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/fastplace/FastPlaceB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/fastplace/FastPlaceB.java new file mode 100644 index 0000000..71dbce0 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/fastplace/FastPlaceB.java @@ -0,0 +1,40 @@ +package me.frep.vulcan.spigot.check.impl.player.fastplace; + +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Fast Place", type = 'B', complexType = "Delay", description = "Placing blocks too quickly.", experimental = true) +public class FastPlaceB extends AbstractCheck +{ + private int blocksPlaced; + + public FastPlaceB(final PlayerData data) { + super(data); + this.blocksPlaced = 0; + } + + @Override + public void handle(final Packet packet) { + if (packet.isBlockPlace()) { + if (System.currentTimeMillis() - this.data.getConnectionProcessor().getLastFlying() > 55L) { + this.blocksPlaced = 0; + } + ++this.blocksPlaced; + } + else if (packet.isFlying()) { + final long flyingDelay = this.data.getConnectionProcessor().getFlyingDelay(); + if (this.blocksPlaced > Config.FASTPLACE_B_MAX_BLOCKS && flyingDelay < 105L) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("blocks=" + this.blocksPlaced + " delay=" + flyingDelay); + } + } + else { + this.decayBuffer(); + } + this.blocksPlaced = 0; + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/fastuse/FastUseA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/fastuse/FastUseA.java new file mode 100644 index 0000000..fd1ff02 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/fastuse/FastUseA.java @@ -0,0 +1,39 @@ +package me.frep.vulcan.spigot.check.impl.player.fastuse; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.BlockUtil; +import org.bukkit.event.player.PlayerItemConsumeEvent; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Fast Use", type = 'A', complexType = "Delay", description = "Using items too quickly.") +public class FastUseA extends AbstractCheck +{ + private long startEat; + + public FastUseA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isBlockPlace()) { + this.startEat = System.currentTimeMillis(); + } + else if (packet.isItemConsumeEvent()) { + final PlayerItemConsumeEvent event = (PlayerItemConsumeEvent)packet.getRawPacket().getRawNMSPacket(); + if (BlockUtil.isKelp(event.getItem().getType())) { + return; + } + final long delay = System.currentTimeMillis() - this.startEat; + final long flyingDelay = this.data.getConnectionProcessor().getFlyingDelay(); + final boolean invalid = delay < 1000L && flyingDelay < 10L; + final boolean exempt = this.isExempt(ExemptType.DROPPED_ITEM, ExemptType.PICKED_UP_ITEM); + if (invalid && !exempt) { + this.fail("delay=" + delay + " item=" + this.data.getPlayer().getItemInHand().getType() + " delay=" + flyingDelay); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/ghosthand/GhostHandA$1.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/ghosthand/GhostHandA$1.java new file mode 100644 index 0000000..3862425 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/ghosthand/GhostHandA$1.java @@ -0,0 +1,4 @@ +package me.frep.vulcan.spigot.check.impl.player.ghosthand; + +import org.bukkit.block.BlockFace; + diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/ghosthand/GhostHandA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/ghosthand/GhostHandA.java new file mode 100644 index 0000000..c0dad00 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/ghosthand/GhostHandA.java @@ -0,0 +1,153 @@ +package me.frep.vulcan.spigot.check.impl.player.ghosthand; + +import java.util.List; +import me.frep.vulcan.spigot.config.Config; +import java.util.function.Predicate; +import me.frep.vulcan.spigot.util.BlockUtil; +import org.bukkit.Material; +import java.util.ArrayList; +import org.bukkit.block.BlockFace; +import org.bukkit.event.block.BlockBreakEvent; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Ghost Hand", type = 'A', complexType = "Bed", description = "Invalid bed break.") +public class GhostHandA extends AbstractCheck +{ + public GhostHandA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isBlockBreakEvent()) { + final BlockBreakEvent event = (BlockBreakEvent)packet.getRawPacket().getRawNMSPacket(); + if (event.getBlock().getType().toString().contains("BED") && !event.getBlock().getType().toString().equalsIgnoreCase("BEDROCK")) { + BlockFace direction = null; + if (this.data.getPositionProcessor().getY() < event.getBlock().getY()) { + return; + } + if (event.getBlock().getLocation().add(0.0, 0.0, 1.0).getBlock().getType().toString().contains("BED")) { + direction = BlockFace.SOUTH; + } + if (event.getBlock().getLocation().add(-1.0, 0.0, 0.0).getBlock().getType().toString().contains("BED")) { + direction = BlockFace.WEST; + } + if (event.getBlock().getLocation().add(0.0, 0.0, -1.0).getBlock().getType().toString().contains("BED")) { + direction = BlockFace.NORTH; + } + if (event.getBlock().getLocation().add(1.0, 0.0, 0.0).getBlock().getType().toString().contains("BED")) { + direction = BlockFace.EAST; + } + if (direction == null) { + return; + } + final List blocks = new ArrayList(); + switch (direction) { + case SOUTH: { + blocks.add(event.getBlock().getLocation().add(0.0, -1.0, 0.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(0.0, -1.0, 1.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(0.0, 0.0, -1.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(-1.0, 0.0, 0.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(1.0, 0.0, 0.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(-1.0, 0.0, 1.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(1.0, 0.0, 1.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(0.0, 0.0, 2.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(0.0, 1.0, 0.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(0.0, 1.0, 1.0).getBlock().getType()); + final boolean invalid68 = blocks.stream().allMatch(Material::isSolid) && blocks.stream().allMatch(Material::isOccluding); + blocks.remove(0); + blocks.remove(0); + final boolean invalid69 = blocks.stream().allMatch(BlockUtil::isSolidGlass); + if (!invalid68 && !invalid69) { + break; + } + this.fail("direction=" + direction + " blocks=" + blocks); + if (Config.GHOSTHAND_A_CANCEL) { + event.setCancelled(true); + break; + } + break; + } + case NORTH: { + blocks.add(event.getBlock().getLocation().add(0.0, -1.0, 0.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(0.0, -1.0, -1.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(0.0, 0.0, 1.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(-1.0, 0.0, 0.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(1.0, 0.0, 0.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(-1.0, 0.0, -1.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(1.0, 0.0, -1.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(0.0, 0.0, -2.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(0.0, 1.0, 0.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(0.0, 1.0, -1.0).getBlock().getType()); + final boolean invalid70 = blocks.stream().allMatch(Material::isSolid) && blocks.stream().allMatch(Material::isOccluding); + blocks.remove(0); + blocks.remove(0); + final boolean invalid71 = blocks.stream().allMatch(BlockUtil::isSolidGlass); + if (!invalid70 && !invalid71) { + break; + } + this.fail("direction=" + direction + " blocks=" + blocks); + if (Config.GHOSTHAND_A_CANCEL) { + event.setCancelled(true); + break; + } + break; + } + case EAST: { + blocks.add(event.getBlock().getLocation().add(0.0, -1.0, 0.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(1.0, -1.0, 0.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(-1.0, 0.0, 0.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(0.0, 0.0, 1.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(0.0, 0.0, -1.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(1.0, 0.0, 1.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(1.0, 0.0, -1.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(2.0, 0.0, 0.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(0.0, 1.0, 0.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(1.0, 1.0, 0.0).getBlock().getType()); + final boolean invalid72 = blocks.stream().allMatch(Material::isSolid) && blocks.stream().allMatch(Material::isOccluding); + blocks.remove(0); + blocks.remove(0); + final boolean invalid73 = blocks.stream().allMatch(BlockUtil::isSolidGlass); + if (!invalid72 && !invalid73) { + break; + } + this.fail("direction=" + direction + " blocks=" + blocks); + if (Config.GHOSTHAND_A_CANCEL) { + event.setCancelled(true); + break; + } + break; + } + case WEST: { + blocks.add(event.getBlock().getLocation().add(0.0, -1.0, 0.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(-1.0, -1.0, 0.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(1.0, 0.0, 0.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(0.0, 0.0, 1.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(0.0, 0.0, -1.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(-1.0, 0.0, 1.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(-1.0, 0.0, -1.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(-2.0, 0.0, 0.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(0.0, 1.0, 0.0).getBlock().getType()); + blocks.add(event.getBlock().getLocation().add(-1.0, 1.0, 0.0).getBlock().getType()); + final boolean invalid74 = blocks.stream().allMatch(Material::isSolid) && blocks.stream().allMatch(Material::isOccluding); + blocks.remove(0); + blocks.remove(0); + final boolean invalid75 = blocks.stream().allMatch(BlockUtil::isSolidGlass); + if (!invalid74 && !invalid75) { + break; + } + this.fail("direction=" + direction + " blocks=" + blocks); + if (Config.GHOSTHAND_A_CANCEL) { + event.setCancelled(true); + break; + } + break; + } + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/groundspoof/GroundSpoofA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/groundspoof/GroundSpoofA.java new file mode 100644 index 0000000..2f8ebb4 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/groundspoof/GroundSpoofA.java @@ -0,0 +1,39 @@ +package me.frep.vulcan.spigot.check.impl.player.groundspoof; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Ground Spoof", type = 'A', complexType = "Spoof", description = "Spoofed onGround value.") +public class GroundSpoofA extends AbstractCheck +{ + public GroundSpoofA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isFlying() && !this.teleporting() && !this.fuckedPosition()) { + final boolean onGround = this.data.getPositionProcessor().isClientOnGround(); + final boolean touchingAir = this.data.getPositionProcessor().isTouchingAir(); + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + if (Math.abs(deltaY) - 0.3116 <= 0.005) { + return; + } + final boolean teleport = this.data.getActionProcessor().getSinceTeleportTicks() < 20; + final int groundTicks = this.data.getPositionProcessor().getClientGroundTicks(); + final boolean exempt = this.isExempt(ExemptType.JOINED, ExemptType.STAIRS, ExemptType.CHUNK, ExemptType.SHULKER, ExemptType.STAIRS, ExemptType.RIPTIDE, ExemptType.LIQUID, ExemptType.TELEPORT, ExemptType.VOID, ExemptType.WORLD_CHANGE, ExemptType.SCAFFOLDING, ExemptType.RIPTIDE, ExemptType.SWIMMING, ExemptType.GLIDING, ExemptType.WATERLOGGED, ExemptType.HONEY, ExemptType.SLOW_FALLING, ExemptType.BLOCK_PLACE, ExemptType.SNOW, ExemptType.WEB, ExemptType.FLIGHT, ExemptType.SLIME, ExemptType.PLACED_SLIME, ExemptType.SHULKER_BOX, ExemptType.NEAR_GROUND, ExemptType.CANCELLED_PLACE, ExemptType.LEVITATION); + final boolean invalid = touchingAir && onGround && deltaY < -0.20000000298023224; + if (invalid && !exempt && !teleport) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaY=" + deltaY + " ticks=" + groundTicks); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/groundspoof/GroundSpoofB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/groundspoof/GroundSpoofB.java new file mode 100644 index 0000000..2f624f6 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/groundspoof/GroundSpoofB.java @@ -0,0 +1,35 @@ +package me.frep.vulcan.spigot.check.impl.player.groundspoof; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Ground Spoof", type = 'B', complexType = "Spoof", description = "Spoofed OnGround value.") +public class GroundSpoofB extends AbstractCheck +{ + public GroundSpoofB(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition()) { + final boolean serverOnGround = this.data.getPositionProcessor().isMathematicallyOnGround(); + final boolean clientOnGround = this.data.getPositionProcessor().isClientOnGround(); + final boolean touchingAir = this.data.getPositionProcessor().isTouchingAir(); + final boolean exempt = this.isExempt(ExemptType.FLIGHT, ExemptType.CREATIVE, ExemptType.BOAT, ExemptType.TELEPORT, ExemptType.SHULKER, ExemptType.SHULKER_BOX, ExemptType.CHUNK, ExemptType.CARPET, ExemptType.VEHICLE, ExemptType.SCAFFOLDING, ExemptType.DEAD); + final double y = this.data.getPositionProcessor().getY(); + final boolean boat = y % 1.0 == 0.6 || y % 0.1 == 0.5625; + if (clientOnGround && !serverOnGround && !exempt && touchingAir && !boat) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("client=" + clientOnGround + " server=" + serverOnGround); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/groundspoof/GroundSpoofC.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/groundspoof/GroundSpoofC.java new file mode 100644 index 0000000..0272bb0 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/groundspoof/GroundSpoofC.java @@ -0,0 +1,34 @@ +package me.frep.vulcan.spigot.check.impl.player.groundspoof; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Ground Spoof", type = 'C', complexType = "Spoof", description = "Spoofed OnGround value.") +public class GroundSpoofC extends AbstractCheck +{ + public GroundSpoofC(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.fuckedPosition()) { + final int airTicks = this.data.getPositionProcessor().getClientAirTicks(); + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final boolean teleport = this.data.getActionProcessor().getSinceTeleportTicks() < 40; + final boolean exempt = this.isExempt(ExemptType.TELEPORT, ExemptType.ANVIL, ExemptType.LIQUID, ExemptType.WATERLOGGED, ExemptType.RIPTIDE, ExemptType.ELYTRA, ExemptType.GLIDING, ExemptType.JOINED, ExemptType.CLIMBABLE, ExemptType.LILY_PAD, ExemptType.SNOW, ExemptType.WORLD_CHANGE, ExemptType.VELOCITY, ExemptType.WEB, ExemptType.NEAR_GROUND, ExemptType.SLOW_FALLING, ExemptType.LEVITATION, ExemptType.SHULKER, ExemptType.SHULKER_BOX, ExemptType.HONEY, ExemptType.SLIME, ExemptType.FLIGHT, ExemptType.BUKKIT_VELOCITY, ExemptType.VOID, ExemptType.CANCELLED_PLACE, ExemptType.PLACED_SLIME, ExemptType.BLOCK_PLACE); + final boolean invalid = deltaY < -0.5 && airTicks < 5; + if (invalid && !exempt && !teleport) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaY=" + deltaY + " airTicks=" + airTicks); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/improbable/ImprobableA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/improbable/ImprobableA.java new file mode 100644 index 0000000..26a648f --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/improbable/ImprobableA.java @@ -0,0 +1,34 @@ +package me.frep.vulcan.spigot.check.impl.player.improbable; + +import me.frep.vulcan.spigot.config.Config; +import io.github.retrooper.packetevents.packetwrappers.play.in.useentity.WrappedPacketInUseEntity; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Improbable", type = 'A', complexType = "Combat", description = "Too many combined combat violations.") +public class ImprobableA extends AbstractCheck +{ + private long lastFlag; + + public ImprobableA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isUseEntity()) { + final WrappedPacketInUseEntity wrapper = this.data.getUseEntityWrapper(); + if (wrapper.getAction() == WrappedPacketInUseEntity.EntityUseAction.ATTACK) { + if (System.currentTimeMillis() - this.lastFlag >= 60000L) { + final int combatViolations = this.data.getCombatViolations(); + if (combatViolations > Config.IMPROBABLE_A_MAX_VIOLATIONS) { + this.fail("combatViolations=" + combatViolations); + this.lastFlag = System.currentTimeMillis(); + } + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/improbable/ImprobableB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/improbable/ImprobableB.java new file mode 100644 index 0000000..b438cda --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/improbable/ImprobableB.java @@ -0,0 +1,30 @@ +package me.frep.vulcan.spigot.check.impl.player.improbable; + +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Improbable", type = 'B', complexType = "Movement", experimental = false, description = "Too many combined movement violations.") +public class ImprobableB extends AbstractCheck +{ + private long lastFlag; + + public ImprobableB(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition()) { + final int movementViolations = this.data.getMovementViolations(); + if (System.currentTimeMillis() - this.lastFlag >= 60000L) { + if (movementViolations > Config.IMPROBABLE_B_MAX_VIOLATIONS) { + this.fail("movementViolations=" + movementViolations); + this.lastFlag = System.currentTimeMillis(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/improbable/ImprobableC.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/improbable/ImprobableC.java new file mode 100644 index 0000000..e104e90 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/improbable/ImprobableC.java @@ -0,0 +1,30 @@ +package me.frep.vulcan.spigot.check.impl.player.improbable; + +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Improbable", type = 'C', complexType = "Player", description = "Too many combined player violations.") +public class ImprobableC extends AbstractCheck +{ + private long lastFlag; + + public ImprobableC(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition()) { + final int playerViolations = this.data.getPlayerViolations(); + if (System.currentTimeMillis() - this.lastFlag >= 60000L) { + if (playerViolations > Config.IMPROBABLE_C_MAX_VIOLATIONS) { + this.fail("playerViolations=" + playerViolations); + this.lastFlag = System.currentTimeMillis(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/improbable/ImprobableD.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/improbable/ImprobableD.java new file mode 100644 index 0000000..62c8d3a --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/improbable/ImprobableD.java @@ -0,0 +1,31 @@ +package me.frep.vulcan.spigot.check.impl.player.improbable; + +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Improbable", type = 'D', complexType = "Auto Clicker", description = "Too many combined autoclicker violations.") +public class ImprobableD extends AbstractCheck +{ + private long lastFlag; + + public ImprobableD(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isArmAnimation() && !this.isExempt(ExemptType.AUTOCLICKER)) { + final int autoClickerViolations = this.data.getAutoClickerViolations(); + if (System.currentTimeMillis() - this.lastFlag >= 60000L) { + if (autoClickerViolations > Config.IMPROBABLE_D_MAX_VIOLATIONS) { + this.fail("autoClickerViolations=" + autoClickerViolations); + this.lastFlag = System.currentTimeMillis(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/improbable/ImprobableE.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/improbable/ImprobableE.java new file mode 100644 index 0000000..4179ce8 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/improbable/ImprobableE.java @@ -0,0 +1,30 @@ +package me.frep.vulcan.spigot.check.impl.player.improbable; + +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Improbable", type = 'E', complexType = "Total", description = "Too many combined violations.") +public class ImprobableE extends AbstractCheck +{ + private long lastFlag; + + public ImprobableE(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isFlying()) { + final int totalViolations = this.data.getTotalViolations(); + if (System.currentTimeMillis() - this.lastFlag >= 60000L) { + if (totalViolations > Config.IMPROBABLE_E_MAX_VIOLATIONS) { + this.fail("totalViolations=" + totalViolations); + this.lastFlag = System.currentTimeMillis(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/improbable/ImprobableF.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/improbable/ImprobableF.java new file mode 100644 index 0000000..23b17e8 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/improbable/ImprobableF.java @@ -0,0 +1,30 @@ +package me.frep.vulcan.spigot.check.impl.player.improbable; + +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Improbable", type = 'F', complexType = "Scaffold", description = "Too many combined Scaffold violations.") +public class ImprobableF extends AbstractCheck +{ + private long lastFlag; + + public ImprobableF(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition()) { + final int scaffoldViolations = this.data.getScaffoldViolations(); + if (System.currentTimeMillis() - this.lastFlag >= 60000L) { + if (scaffoldViolations > Config.IMPROBABLE_F_MAX_SCAFFOLD_VIOLATIONS) { + this.fail("scaffoldViolations=" + scaffoldViolations); + this.lastFlag = System.currentTimeMillis(); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidA.java new file mode 100644 index 0000000..a9e86ff --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidA.java @@ -0,0 +1,41 @@ +package me.frep.vulcan.spigot.check.impl.player.invalid; + +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Invalid", type = 'A', complexType = "A", description = "Moving too quickly.", experimental = true) +public class InvalidA extends AbstractCheck +{ + public InvalidA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting()) { + final boolean flight = this.isExempt(ExemptType.FLIGHT) && !this.data.getPlayer().getAllowFlight(); + final boolean exempt = this.isExempt(ExemptType.TELEPORT, ExemptType.WORLD_CHANGE, ExemptType.JOINED, ExemptType.VEHICLE, ExemptType.RESPAWN, ExemptType.ELYTRA, ExemptType.GLIDING, ExemptType.FIREWORK, ExemptType.RIPTIDE); + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double flySpeed = this.data.getPositionProcessor().getFlySpeed(); + double max = PlayerUtil.getBaseSpeed(this.data, 1.2f); + if (this.data.getVelocityProcessor().getTransactionFlyingTicks() < 30) { + max += this.data.getVelocityProcessor().getVelocityXZ() + 0.05; + } + final double difference = deltaXZ - max; + final int sinceTeleportTicks = this.data.getActionProcessor().getSinceTeleportTicks(); + final boolean spectator = this.data.getPositionProcessor().getSinceSpectatorTicks() < 50; + if (!exempt && flight && deltaXZ > max && flySpeed < 0.10999999940395355 && !spectator) { + if (this.increaseBuffer() > this.MAX_BUFFER || (difference > 1.0 && sinceTeleportTicks > 5)) { + this.fail("dXZ=" + deltaXZ + " max=" + max); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidC.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidC.java new file mode 100644 index 0000000..bd0d8e7 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidC.java @@ -0,0 +1,35 @@ +package me.frep.vulcan.spigot.check.impl.player.invalid; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Invalid", type = 'C', complexType = "Y", description = "Too large Y-Axis movement.") +public class InvalidC extends AbstractCheck +{ + public InvalidC(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting() && !this.fuckedPosition()) { + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final boolean bukkitTeleport = this.data.getActionProcessor().getSinceBukkitTeleportTicks() < 80; + final boolean death = this.data.getActionProcessor().getSinceDeathTicks() < 40; + final boolean joined = System.currentTimeMillis() - this.data.getJoinTime() < 10000L; + final boolean exempt = this.isExempt(ExemptType.TELEPORT, ExemptType.RIPTIDE, ExemptType.GLIDING, ExemptType.FISHING_ROD, ExemptType.VELOCITY, ExemptType.JOINED, ExemptType.FLIGHT, ExemptType.CREATIVE, ExemptType.VEHICLE, ExemptType.WORLD_CHANGE, ExemptType.DOLPHINS_GRACE, ExemptType.SOUL_SPEED, ExemptType.DEATH, ExemptType.RIPTIDE, ExemptType.SLEEPING, ExemptType.ENDER_PEARL, ExemptType.HIGH_JUMP_BOOST, ExemptType.HIGH_LEVITATION); + final boolean invalid = Math.abs(deltaY) > 3.9210000038146973; + if (invalid && !exempt && !bukkitTeleport && !death && !joined) { + if (this.increaseBuffer() > this.MAX_BUFFER || (deltaY > 4.0 && this.isExempt(ExemptType.SERVER_POSITION))) { + this.fail("deltaY=" + deltaY); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidD.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidD.java new file mode 100644 index 0000000..63d87fe --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidD.java @@ -0,0 +1,35 @@ +package me.frep.vulcan.spigot.check.impl.player.invalid; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Invalid", type = 'D', complexType = "Acceleration", description = "Large yaw changes without decelerating.") +public class InvalidD extends AbstractCheck +{ + public InvalidD(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPositionLook()) { + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double acceleration = this.data.getPositionProcessor().getAcceleration(); + final float deltaYaw = this.data.getRotationProcessor().getDeltaYaw(); + final float lastDeltaYaw = this.data.getRotationProcessor().getLastDeltaYaw(); + final boolean invalid = acceleration < 1.0E-5 && deltaYaw > 15.0f && lastDeltaYaw > 15.0f && deltaXZ > 0.2; + final boolean exempt = this.isExempt(ExemptType.GLIDING, ExemptType.RIPTIDE, ExemptType.ELYTRA, ExemptType.SPECTATOR, ExemptType.POWDER_SNOW, ExemptType.WEB); + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaYaw=" + deltaYaw + " acceleration=" + acceleration); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidE.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidE.java new file mode 100644 index 0000000..efe6e5a --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidE.java @@ -0,0 +1,32 @@ +package me.frep.vulcan.spigot.check.impl.player.invalid; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Invalid", type = 'E', complexType = "X/Z", description = "Too large X/Z-Axis movement.") +public class InvalidE extends AbstractCheck +{ + public InvalidE(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting() && !this.fuckedPosition()) { + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final boolean exempt = this.isExempt(ExemptType.TELEPORT, ExemptType.RIPTIDE, ExemptType.GLIDING, ExemptType.ATTRIBUTE_MODIFIER, ExemptType.VELOCITY, ExemptType.JOINED, ExemptType.FLIGHT, ExemptType.CREATIVE, ExemptType.VEHICLE, ExemptType.WORLD_CHANGE, ExemptType.DOLPHINS_GRACE, ExemptType.SOUL_SPEED, ExemptType.CHORUS_FRUIT, ExemptType.RIPTIDE, ExemptType.SLEEPING, ExemptType.LEVITATION, ExemptType.ENDER_PEARL, ExemptType.ENTITY_CRAM_FIX, ExemptType.HIGH_SPEED, ExemptType.SHULKER_BOX, ExemptType.SHULKER, ExemptType.CHUNK); + final boolean invalid = deltaXZ > 3.5 && deltaXZ < 100.0; + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaXZ=" + deltaXZ); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidF.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidF.java new file mode 100644 index 0000000..b51efc4 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidF.java @@ -0,0 +1,31 @@ +package me.frep.vulcan.spigot.check.impl.player.invalid; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Invalid", type = 'F', complexType = "Spoofed Y", description = "Impossible Y-axis change.") +public class InvalidF extends AbstractCheck +{ + public InvalidF(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting()) { + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final boolean exempt = this.isExempt(ExemptType.DEATH, ExemptType.JOINED, ExemptType.TELEPORT, ExemptType.WORLD_CHANGE); + if (Math.abs(deltaY) > 100.0 && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaY=" + deltaY); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidG.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidG.java new file mode 100644 index 0000000..2afe544 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidG.java @@ -0,0 +1,38 @@ +package me.frep.vulcan.spigot.check.impl.player.invalid; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Invalid", type = 'G', complexType = "Invalid X/Z movement", description = "Impossible X/Z change.") +public class InvalidG extends AbstractCheck +{ + public InvalidG(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting()) { + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + double max = PlayerUtil.getBaseSpeed(this.data, 1.0f); + if (this.isExempt(ExemptType.VELOCITY)) { + max += this.data.getVelocityProcessor().getVelocityXZ(); + } + final boolean exempt = this.isExempt(ExemptType.JOINED, ExemptType.HIGH_FLY_SPEED, ExemptType.DOLPHINS_GRACE, ExemptType.ATTRIBUTE_MODIFIER, ExemptType.ELYTRA, ExemptType.GLIDING, ExemptType.RIPTIDE, ExemptType.VEHICLE, ExemptType.ENDER_PEARL, ExemptType.CHORUS_FRUIT, ExemptType.SLIME, ExemptType.AROUND_SLIME); + final boolean exploit = this.isExempt(ExemptType.FLIGHT) && !this.data.getPositionProcessor().isAllowFlight(); + final boolean walkSpeed = this.data.getPositionProcessor().getFlySpeed() > 0.11f; + if (exploit && !exempt && deltaXZ > max && !walkSpeed) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaXZ=" + deltaXZ + " ticks=" + this.data.getPositionProcessor().getSinceFlyingTicks()); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidI.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidI.java new file mode 100644 index 0000000..4b0e148 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidI.java @@ -0,0 +1,68 @@ +package me.frep.vulcan.spigot.check.impl.player.invalid; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Invalid", type = 'I', complexType = "Invalid Y movement", description = "Impossible Y change.") +public class InvalidI extends AbstractCheck +{ + public InvalidI(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting()) { + if (PlayerUtil.isHigherThan1_9(this.data.getPlayer())) { + return; + } + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final int airTicks = this.data.getPositionProcessor().getClientAirTicks(); + final boolean damage = this.data.getActionProcessor().getSinceNonFallDamageTicks() < 20; + final boolean bed = this.data.getPositionProcessor().getSinceNearBedTicks() < 40; + final boolean explosion = this.data.getActionProcessor().getSinceExplosionDamageTicks() < 100; + final boolean golem = this.data.getActionProcessor().getSinceIronGolemDamageTicks() < 30; + final boolean dragon = this.data.getActionProcessor().getSinceDragonDamageTicks() < 200; + final boolean fireball = this.isExempt(ExemptType.FIREBALL); + final boolean exploit = this.isExempt(ExemptType.VEHICLE); + final boolean exempt = this.isExempt(ExemptType.JOINED, ExemptType.TELEPORT, ExemptType.RIPTIDE, ExemptType.HONEY, ExemptType.GLIDING, ExemptType.LEVITATION, ExemptType.SLAB, ExemptType.STAIRS, ExemptType.FLIGHT, ExemptType.JUMP_BOOST_RAN_OUT, ExemptType.ELYTRA, ExemptType.BUBBLE_COLUMN, ExemptType.WALL, ExemptType.CREATIVE, ExemptType.SHULKER_BOX, ExemptType.STAIRS, ExemptType.ANVIL, ExemptType.SLIME, ExemptType.PISTON, ExemptType.TURTLE_EGG, ExemptType.DOOR, ExemptType.DEATH, ExemptType.ENDER_PEARL, ExemptType.PLACED_SLIME, ExemptType.BUKKIT_VELOCITY, ExemptType.CHORUS_FRUIT, ExemptType.MYTHIC_MOB, ExemptType.BLOCK_BREAK, ExemptType.FISHING_ROD, ExemptType.SLEEPING, ExemptType.SHULKER); + double limit = 1.25; + if (golem) { + limit += 0.4000000059604645; + } + if (fireball) { + limit += 0.5; + } + if (this.isExempt(ExemptType.BOAT)) { + limit += 0.125; + } + if (this.isExempt(ExemptType.SKULL)) { + limit += 0.1; + } + if (this.data.getPositionProcessor().isNearPowderSnow()) { + limit += 0.3; + } + if (this.data.getActionProcessor().getSinceHoglinDamageTicks() < 20) { + limit += 0.15000000596046448; + } + if (this.data.getActionProcessor().isHasJumpBoost()) { + limit += this.data.getActionProcessor().getJumpBoostAmplifier() * 0.125f; + } + if (this.isExempt(ExemptType.FENCE)) { + limit += 0.25; + } + if (airTicks > 0 && deltaY > limit && !damage && !exempt && !bed && !explosion && !dragon && exploit) { + if (this.increaseBuffer() > this.MAX_BUFFER || deltaY > 2.5) { + this.fail("deltaY=" + deltaY + " limit=" + limit); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidJ.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidJ.java new file mode 100644 index 0000000..e65e703 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/invalid/InvalidJ.java @@ -0,0 +1,432 @@ +package me.frep.vulcan.spigot.check.impl.player.invalid; + +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Invalid", type = 'J', complexType = "Motion", description = "Moving too quickly.", experimental = true) +public class InvalidJ extends AbstractCheck +{ + public InvalidJ(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isPosition() && !this.teleporting()) { + final boolean stuck = this.data.getPositionProcessor().isFullyStuck() || this.data.getPositionProcessor().isPartiallyStuck(); + if (!stuck) { + return; + } + if (this.data.getActionProcessor().getJumpBoostAmplifier() > 50) { + return; + } + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final int groundTicks = this.data.getPositionProcessor().getClientGroundTicks(); + final int sinceCollidingVerticallyTicks = this.data.getPositionProcessor().getSinceCollidingVerticallyTicks(); + final int sinceIceTicks = this.data.getPositionProcessor().getSinceIceTicks(); + final int sinceSlimeTicks = this.data.getPositionProcessor().getSinceNearSlimeTicks(); + final int sinceVelocityTicks = this.data.getVelocityProcessor().getTransactionFlyingTicks(); + final int sinceTrapdoorTicks = this.data.getPositionProcessor().getSinceTrapdoorTicks(); + final int sinceNearFenceTicks = this.data.getPositionProcessor().getSinceNearFenceTicks(); + final int sinceNearBedTicks = this.data.getPositionProcessor().getSinceNearBedTicks(); + final boolean wasCollidingVertically = sinceCollidingVerticallyTicks < 45; + final boolean wasOnIce = sinceIceTicks < 60; + final boolean wasNearBed = sinceNearBedTicks < 30; + final boolean nearStair = this.data.getPositionProcessor().isNearStair(); + final boolean wasOnSlime = sinceSlimeTicks < 30; + final boolean wasNearTrapdoor = sinceTrapdoorTicks < 40; + final boolean depthStrider = this.isExempt(ExemptType.DEPTH_STRIDER); + final boolean nearSlab = this.data.getPositionProcessor().isNearSlab(); + final boolean wasNearFence = sinceNearFenceTicks < 20; + final boolean soulSpeed = this.data.getPositionProcessor().getSinceSoulSpeedTicks() < 30; + final boolean wasNearSlime = this.data.getPositionProcessor().getSinceNearSlimeTicks() < 30; + double maxSpeed = PlayerUtil.getBaseGroundSpeed(this.data); + switch (groundTicks) { + case 0: { + maxSpeed += 0.03; + if (wasOnIce) { + maxSpeed += 0.08; + } + if (nearStair) { + maxSpeed += 0.35; + } + if (wasCollidingVertically && wasOnIce) { + maxSpeed += 0.35; + } + if (wasOnSlime) { + maxSpeed += 0.05; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.6; + } + if (nearSlab) { + maxSpeed += 0.04; + } + if (sinceIceTicks == 0 && nearSlab) { + maxSpeed += 0.1; + } + if (wasNearTrapdoor) { + maxSpeed += 0.1; + } + if (wasNearFence) { + maxSpeed += 0.1; + } + if (deltaY == 0.41999998688697815) { + maxSpeed += 0.03; + break; + } + break; + } + case 1: { + maxSpeed += 0.025; + if (wasOnIce) { + maxSpeed += 0.1; + } + if (nearStair) { + maxSpeed += 0.35; + } + if (wasCollidingVertically && wasOnIce) { + maxSpeed += 0.45; + } + if (wasOnSlime) { + maxSpeed += 0.05; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.55; + } + if (nearSlab) { + maxSpeed += 0.15; + } + if (wasNearTrapdoor) { + maxSpeed += 0.1; + } + if (wasNearFence) { + maxSpeed += 0.1; + break; + } + break; + } + case 2: { + maxSpeed += 0.134; + if (wasCollidingVertically && !stuck) { + maxSpeed += 0.06694; + } + if (wasOnIce) { + maxSpeed += 0.08; + } + if (wasNearBed) { + maxSpeed += 0.04; + } + if (nearStair) { + maxSpeed += 0.35; + } + if (wasCollidingVertically && wasOnIce) { + maxSpeed += 0.4; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.55; + } + if (nearSlab) { + maxSpeed += 0.15; + } + if (wasNearTrapdoor) { + maxSpeed += 0.1; + } + if (sinceIceTicks == 0 && nearSlab) { + maxSpeed += 0.005; + } + if (wasNearFence) { + maxSpeed += 0.1; + break; + } + break; + } + case 3: { + maxSpeed += 0.0693; + if (wasCollidingVertically && !stuck) { + maxSpeed += 0.036; + } + if (wasOnIce) { + maxSpeed += 0.045; + } + if (nearStair) { + maxSpeed += 0.35; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.35; + } + if (wasCollidingVertically && wasOnIce) { + maxSpeed += 0.35; + } + if (nearSlab) { + maxSpeed += 0.04; + } + if (wasNearBed) { + maxSpeed += 0.04; + } + if (wasNearFence) { + maxSpeed += 0.1; + } + if (wasNearTrapdoor) { + maxSpeed += 0.1; + break; + } + break; + } + case 4: { + maxSpeed += 0.035; + if (wasCollidingVertically && !stuck) { + maxSpeed += 0.0211; + } + if (wasOnIce) { + maxSpeed += 0.03; + } + if (nearStair) { + maxSpeed += 0.35; + } + if (wasNearTrapdoor) { + maxSpeed += 0.1; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.35; + } + if (wasCollidingVertically && wasOnIce) { + maxSpeed += 0.35; + } + if (nearSlab) { + maxSpeed += 0.04; + break; + } + break; + } + case 5: { + maxSpeed += 0.0205; + if (wasCollidingVertically && !stuck) { + maxSpeed += 0.0231; + } + if (wasOnIce) { + maxSpeed += 0.03; + } + if (nearStair) { + maxSpeed += 0.35; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.35; + } + if (nearSlab) { + maxSpeed += 0.04; + break; + } + break; + } + case 6: { + maxSpeed += 0.009; + if (wasCollidingVertically && !stuck) { + maxSpeed += 0.0027; + } + if (wasOnIce) { + maxSpeed += 0.02; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.35; + } + if (nearSlab) { + maxSpeed += 0.04; + break; + } + break; + } + case 7: { + maxSpeed += 0.005; + if (wasOnIce) { + maxSpeed += 0.02; + } + if (wasNearTrapdoor && wasOnIce) { + maxSpeed += 0.1; + break; + } + break; + } + case 8: { + maxSpeed += 0.003; + if (wasOnIce) { + maxSpeed += 0.02; + } + if (sinceIceTicks == 0 && nearSlab) { + maxSpeed += 0.02; + break; + } + break; + } + case 9: { + maxSpeed += 0.0025; + if (wasOnIce) { + maxSpeed += 0.02; + break; + } + break; + } + } + if (sinceIceTicks == 0) { + if (groundTicks > 2 && groundTicks < 9) { + maxSpeed += 0.09; + } + else if (groundTicks >= 9 && groundTicks < 15) { + maxSpeed += 0.09; + } + else if (groundTicks >= 15) { + maxSpeed += 0.09; + } + } + if (this.isExempt(ExemptType.FARMLAND)) { + maxSpeed += 0.05; + } + if (sinceIceTicks < 30 && groundTicks >= 5 && groundTicks <= 25 && wasCollidingVertically) { + maxSpeed += 0.15; + } + if (this.isExempt(ExemptType.CANCELLED_PLACE)) { + maxSpeed += 0.08; + } + if (sinceIceTicks < 30 && groundTicks > 8) { + maxSpeed += 0.15; + } + if (depthStrider) { + maxSpeed += 0.1; + } + if (ServerUtil.isHigherThan1_16() && soulSpeed && this.data.getActionProcessor().getSpeedAmplifier() > 3) { + maxSpeed += 1.25; + } + if (ServerUtil.isHigherThan1_16() && soulSpeed) { + maxSpeed += 0.5; + } + if (wasOnIce && wasNearSlime) { + maxSpeed += 0.35; + } + if (wasNearSlime && wasCollidingVertically) { + maxSpeed += 0.1; + } + if (this.isExempt(ExemptType.SLAB)) { + maxSpeed += 0.3; + } + if (this.isExempt(ExemptType.STAIRS)) { + maxSpeed += 0.5; + } + final double velocityXZ = this.data.getVelocityProcessor().getVelocityXZ(); + switch (sinceVelocityTicks) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: { + maxSpeed += velocityXZ + 0.05; + break; + } + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: { + maxSpeed += velocityXZ * 0.75; + break; + } + case 16: + case 17: + case 18: + case 19: + case 20: { + maxSpeed += velocityXZ * 0.6; + break; + } + case 21: + case 22: + case 23: + case 24: + case 25: { + maxSpeed += velocityXZ * 0.5; + break; + } + case 26: + case 27: + case 28: + case 29: + case 30: { + maxSpeed += velocityXZ * 0.35; + break; + } + case 31: + case 32: + case 33: + case 34: + case 35: { + maxSpeed += velocityXZ * 0.25; + break; + } + case 36: + case 37: + case 38: + case 39: + case 40: { + maxSpeed += velocityXZ * 0.1; + break; + } + } + if (this.data.getPositionProcessor().getSinceAroundSlimeTicks() < 15) { + maxSpeed += 0.7; + } + if (ServerUtil.isHigherThan1_9() && Config.ENTITY_COLLISION_FIX && this.data.getPositionProcessor().getSinceEntityCollisionTicks() < 20) { + maxSpeed += 0.1; + } + if (this.data.getActionProcessor().getSinceIcePlaceTicks() < 35) { + maxSpeed += 0.2; + } + if (this.isExempt(ExemptType.PISTON)) { + maxSpeed += 0.325; + } + if (this.data.getPositionProcessor().getSinceAroundSlabTicks() < 5) { + maxSpeed += 0.025; + } + if (this.isExempt(ExemptType.BUKKIT_VELOCITY)) { + maxSpeed += velocityXZ * 2.0; + } + if (this.isExempt(ExemptType.SPEED_RAN_OUT)) { + ++maxSpeed; + } + if (this.isExempt(ExemptType.SNOW)) { + maxSpeed += 0.05; + } + if (this.data.getActionProcessor().getSinceRavagerDamageTicks() < 30) { + maxSpeed += 2.0; + } + if (this.data.getActionProcessor().getSinceCrystalDamageTicks() < 5) { + maxSpeed += 0.65; + } + else if (this.data.getActionProcessor().getSinceCrystalDamageTicks() > 5 && this.data.getActionProcessor().getSinceCrystalDamageTicks() < 25) { + maxSpeed += 0.3; + } + final double difference = deltaXZ - maxSpeed; + final boolean exempt = this.isExempt(ExemptType.FLIGHT, ExemptType.JOINED, ExemptType.CREATIVE, ExemptType.SHULKER, ExemptType.SHULKER_BOX, ExemptType.BAMBOO, ExemptType.CAKE, ExemptType.PRESSURE_PLATE, ExemptType.CHUNK, ExemptType.DOLPHINS_GRACE, ExemptType.TELEPORT, ExemptType.ILLEGAL_BLOCK, ExemptType.GLIDING, ExemptType.DOOR, ExemptType.RIPTIDE, ExemptType.VEHICLE, ExemptType.BOAT, ExemptType.FISHING_ROD, ExemptType.ELYTRA, ExemptType.SIGN, ExemptType.DEATH, ExemptType.SLEEPING, ExemptType.ENDER_PEARL, ExemptType.FROZEN, ExemptType.CHORUS_FRUIT, ExemptType.SPECTATOR, ExemptType.WORLD_CHANGE, ExemptType.ATTRIBUTE_MODIFIER, ExemptType.ANVIL, ExemptType.CANCELLED_MOVE, ExemptType.GLASS_PANE, ExemptType.FENCE, ExemptType.BED); + final boolean invalid = difference > Config.SPEED_B_MIN_DIFFERENCE && groundTicks >= 0; + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER || (difference > 0.5 && difference < 100.0 && !this.isExempt(ExemptType.SERVER_POSITION, ExemptType.CHORUS_FRUIT))) { + this.fail("speed=" + deltaXZ + " max=" + maxSpeed + " diff=" + difference + " ticks=" + groundTicks + " deltaY=" + deltaY); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/inventory/InventoryA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/inventory/InventoryA.java new file mode 100644 index 0000000..3b5218e --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/inventory/InventoryA.java @@ -0,0 +1,35 @@ +package me.frep.vulcan.spigot.check.impl.player.inventory; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import io.github.retrooper.packetevents.packetwrappers.play.in.windowclick.WrappedPacketInWindowClick; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Inventory", type = 'A', complexType = "Sprint", description = "Sprinting while clicking in inventory.") +public class InventoryA extends AbstractCheck +{ + public InventoryA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isWindowClick()) { + final WrappedPacketInWindowClick wrapper = new WrappedPacketInWindowClick(packet.getRawPacket()); + final int sprintingTicks = this.data.getActionProcessor().getSprintingTicks(); + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final boolean exempt = this.isExempt(ExemptType.VEHICLE, ExemptType.TELEPORT, ExemptType.WORLD_CHANGE, ExemptType.SERVER_POSITION, ExemptType.ELYTRA, ExemptType.GLIDING, ExemptType.FIREWORK); + final boolean invalid = sprintingTicks > 5 && deltaXZ > 0.25; + if (invalid && !exempt && wrapper.getWindowId() == 0) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + sprintingTicks); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/inventory/InventoryB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/inventory/InventoryB.java new file mode 100644 index 0000000..d7997b0 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/inventory/InventoryB.java @@ -0,0 +1,33 @@ +package me.frep.vulcan.spigot.check.impl.player.inventory; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Inventory", type = 'B', complexType = "Move", description = "Moved while clicking in inventory.") +public class InventoryB extends AbstractCheck +{ + public InventoryB(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isWindowClick()) { + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double lastDeltaXZ = this.data.getPositionProcessor().getLastDeltaXZ(); + final boolean accelerating = deltaXZ > lastDeltaXZ && deltaXZ > 0.2; + final boolean exempt = this.isExempt(ExemptType.VELOCITY, ExemptType.ENDER_PEARL, ExemptType.FLIGHT, ExemptType.SPECTATOR, ExemptType.RIPTIDE, ExemptType.GLIDING, ExemptType.ELYTRA, ExemptType.SHULKER_BOX, ExemptType.SHULKER, ExemptType.ICE, ExemptType.DRAGON_DAMAGE, ExemptType.JOINED, ExemptType.TELEPORT, ExemptType.PISTON, ExemptType.WATERLOGGED, ExemptType.LIQUID, ExemptType.SWIMMING, ExemptType.SERVER_POSITION, ExemptType.BOAT, ExemptType.SLIME, ExemptType.WORLD_CHANGE, ExemptType.SOUL_SPEED, ExemptType.DOLPHINS_GRACE, ExemptType.BUBBLE_COLUMN, ExemptType.HIGH_SPEED, ExemptType.VEHICLE); + if (accelerating && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaXZ=" + deltaXZ + " lastDeltaXZ=" + lastDeltaXZ); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldA.java new file mode 100644 index 0000000..7924909 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldA.java @@ -0,0 +1,34 @@ +package me.frep.vulcan.spigot.check.impl.player.scaffold; + +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Scaffold", type = 'A', complexType = "Interact", description = "Interacted with the bottom of block.") +public class ScaffoldA extends AbstractCheck +{ + public ScaffoldA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isInteractEvent()) { + final PlayerInteractEvent event = (PlayerInteractEvent)packet.getRawPacket().getRawNMSPacket(); + if (event.getAction().equals(Action.RIGHT_CLICK_BLOCK)) { + final Block below = this.data.getPlayer().getLocation().subtract(0.0, 1.0, 0.0).getBlock(); + final boolean exempt = this.isExempt(ExemptType.TELEPORT, ExemptType.SERVER_POSITION); + final boolean invalid = event.getClickedBlock() != null && event.getClickedBlock().equals(below) && event.getBlockFace() == BlockFace.DOWN && event.getClickedBlock().getType().isSolid() && this.data.getPlayer().getItemInHand().getType().isSolid(); + if (invalid && !exempt) { + this.fail("block=" + event.getClickedBlock().getType()); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldB.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldB.java new file mode 100644 index 0000000..125d5cc --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldB.java @@ -0,0 +1,46 @@ +package me.frep.vulcan.spigot.check.impl.player.scaffold; + +import org.bukkit.block.BlockFace; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.BlockUtil; +import me.frep.vulcan.spigot.util.PlayerUtil; +import org.bukkit.event.block.BlockPlaceEvent; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Scaffold", type = 'B', complexType = "Interact", experimental = false, description = "Invalid interact.") +public class ScaffoldB extends AbstractCheck +{ + private long lastPlace; + + public ScaffoldB(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isBlockPlaceEvent()) { + final BlockPlaceEvent event = (BlockPlaceEvent)packet.getRawPacket().getRawNMSPacket(); + if (event.isCancelled()) { + return; + } + final boolean bridging = PlayerUtil.isBridging(event); + final long delay = System.currentTimeMillis() - this.lastPlace; + final BlockFace face = event.getBlockAgainst().getFace(event.getBlock()); + final boolean invalidBlock = BlockUtil.isTurtleEgg(event.getBlock()) || BlockUtil.isSlab(event.getBlock()); + final boolean exempt = this.isExempt(ExemptType.LIQUID, ExemptType.CREATIVE, ExemptType.FLIGHT, ExemptType.TURTLE_EGG, ExemptType.SLAB); + final boolean invalid = bridging && face == BlockFace.SELF && delay < 300L; + if (invalid && !exempt && !invalidBlock) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("delay=" + delay + " face=" + face.toString().toLowerCase()); + } + } + else { + this.decayBuffer(); + } + this.lastPlace = System.currentTimeMillis(); + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldC.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldC.java new file mode 100644 index 0000000..71d0735 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldC.java @@ -0,0 +1,43 @@ +package me.frep.vulcan.spigot.check.impl.player.scaffold; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.PlayerUtil; +import org.bukkit.event.block.BlockPlaceEvent; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Scaffold", type = 'C', complexType = "Sprint", description = "Sprinting while bridging.") +public class ScaffoldC extends AbstractCheck +{ + private long lastPlace; + + public ScaffoldC(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isBlockPlaceEvent()) { + final BlockPlaceEvent event = (BlockPlaceEvent)packet.getRawPacket().getRawNMSPacket(); + if (event.isCancelled()) { + return; + } + final boolean bridging = PlayerUtil.isBridging(event); + final long delay = System.currentTimeMillis() - this.lastPlace; + final int sprintingTicks = this.data.getActionProcessor().getSprintingTicks(); + final boolean exempt = this.isExempt(ExemptType.LIQUID, ExemptType.CREATIVE, ExemptType.FLIGHT); + final boolean invalid = bridging && delay < 300L && sprintingTicks > 5; + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("ticks=" + sprintingTicks + " delay=" + delay); + } + } + else { + this.decayBuffer(); + } + this.lastPlace = System.currentTimeMillis(); + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldD.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldD.java new file mode 100644 index 0000000..73de21a --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldD.java @@ -0,0 +1,53 @@ +package me.frep.vulcan.spigot.check.impl.player.scaffold; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.util.PlayerUtil; +import org.bukkit.event.block.BlockPlaceEvent; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Scaffold", type = 'D', complexType = "Rotations", experimental = false, description = "Invalid rotations.") +public class ScaffoldD extends AbstractCheck +{ + private long lastPlace; + private long delay; + private boolean bridging; + private int placeTicks; + + public ScaffoldD(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isBlockPlaceEvent()) { + final BlockPlaceEvent event = (BlockPlaceEvent)packet.getRawPacket().getRawNMSPacket(); + if (event.isCancelled()) { + return; + } + this.bridging = PlayerUtil.isBridging(event); + this.delay = System.currentTimeMillis() - this.lastPlace; + this.placeTicks = 0; + this.lastPlace = System.currentTimeMillis(); + } + else if (packet.isRotation() && ++this.placeTicks < 6 && this.bridging && this.delay < 400L) { + final float lastDeltaPitch = this.data.getRotationProcessor().getLastDeltaPitch(); + final float deltaPitch = this.data.getRotationProcessor().getDeltaPitch(); + final long expandedPitch = (long)(MathUtil.EXPANDER * deltaPitch); + final long expandedLastPitch = (long)(MathUtil.EXPANDER * lastDeltaPitch); + final long gcd = MathUtil.getGcd(expandedPitch, expandedLastPitch); + final boolean exempt = this.isExempt(ExemptType.CINEMATIC); + if (gcd < 131072L && gcd > 0L && deltaPitch > 0.15 && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("rotation=" + gcd / 100L); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldE.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldE.java new file mode 100644 index 0000000..247a7d9 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldE.java @@ -0,0 +1,47 @@ +package me.frep.vulcan.spigot.check.impl.player.scaffold; + +import me.frep.vulcan.spigot.util.PlayerUtil; +import org.bukkit.event.block.BlockPlaceEvent; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Scaffold", type = 'E', complexType = "Rotations [2]", experimental = false, description = "Invalid rotations.") +public class ScaffoldE extends AbstractCheck +{ + private long lastPlace; + private long delay; + private boolean bridging; + private int placeTicks; + + public ScaffoldE(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isBlockPlaceEvent()) { + final BlockPlaceEvent event = (BlockPlaceEvent)packet.getRawPacket().getRawNMSPacket(); + if (event.isCancelled()) { + return; + } + this.bridging = PlayerUtil.isBridging(event); + this.delay = System.currentTimeMillis() - this.lastPlace; + this.placeTicks = 0; + this.lastPlace = System.currentTimeMillis(); + } + else if (packet.isFlying() && ++this.placeTicks < 3 && this.bridging && this.delay < 400L) { + final float deltaPitch = this.data.getRotationProcessor().getDeltaPitch(); + final float deltaYaw = this.data.getRotationProcessor().getDeltaYaw(); + if (deltaPitch > 8.0f && deltaYaw > 100.0f) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("deltaYaw=" + deltaYaw + " deltaPitch=" + deltaPitch); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldF.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldF.java new file mode 100644 index 0000000..c3e1ac9 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldF.java @@ -0,0 +1,62 @@ +package me.frep.vulcan.spigot.check.impl.player.scaffold; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import io.github.retrooper.packetevents.packetwrappers.play.in.entityaction.WrappedPacketInEntityAction; +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.util.BlockUtil; +import org.bukkit.event.block.BlockPlaceEvent; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Scaffold", type = 'F', complexType = "Packet", description = "Invalid rotations") +public class ScaffoldF extends AbstractCheck +{ + private long lastPlace; + private long delay; + private long lastSneak; + private long sneakDelay; + private boolean bridging; + private boolean sneak; + + public ScaffoldF(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isBlockPlaceEvent()) { + final BlockPlaceEvent event = (BlockPlaceEvent)packet.getRawPacket().getRawNMSPacket(); + if (event.isCancelled() || BlockUtil.isScaffolding(event.getBlock().getType())) { + return; + } + this.bridging = PlayerUtil.isBridging(event); + this.delay = System.currentTimeMillis() - this.lastPlace; + this.lastPlace = System.currentTimeMillis(); + } + else if (packet.isEntityAction()) { + final WrappedPacketInEntityAction wrapper = this.data.getEntityActionWrapper(); + if (wrapper.getAction() == WrappedPacketInEntityAction.PlayerAction.START_SNEAKING || wrapper.getAction() == WrappedPacketInEntityAction.PlayerAction.STOP_SNEAKING) { + this.sneakDelay = System.currentTimeMillis() - this.lastSneak; + this.sneak = true; + this.lastSneak = System.currentTimeMillis(); + } + } + else if (packet.isPosition()) { + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double max = PlayerUtil.getBaseSpeed(this.data, 0.27f); + final boolean exempt = this.isExempt(ExemptType.LIQUID, ExemptType.FLIGHT, ExemptType.CREATIVE); + final boolean invalid = this.sneak && this.bridging && deltaXZ > max && this.delay < 400L; + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("delay=" + this.delay + " delta=" + deltaXZ + " sd=" + this.sneakDelay); + } + } + else { + this.decayBuffer(); + } + this.sneak = false; + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldG.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldG.java new file mode 100644 index 0000000..b215a95 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldG.java @@ -0,0 +1,47 @@ +package me.frep.vulcan.spigot.check.impl.player.scaffold; + +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.BlockUtil; +import org.bukkit.event.block.BlockPlaceEvent; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Scaffold", type = 'G', complexType = "Speed", experimental = false, description = "Bridging too quickly.") +public class ScaffoldG extends AbstractCheck +{ + private long lastPlace; + + public ScaffoldG(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isBlockPlaceEvent()) { + final BlockPlaceEvent event = (BlockPlaceEvent)packet.getRawPacket().getRawNMSPacket(); + if (event.isCancelled() || BlockUtil.isSlab(event.getBlock().getType()) || this.isExempt(ExemptType.SLAB)) { + return; + } + final boolean bridging = PlayerUtil.isBridging(event); + if (bridging) { + final long delay = System.currentTimeMillis() - this.lastPlace; + final float angle = this.data.getRotationProcessor().getMovementAngle(); + final double acceleration = this.data.getPositionProcessor().getAcceleration(); + final boolean exempt = BlockUtil.isScaffolding(event.getBlock()); + final boolean invalid = acceleration < 0.001 && acceleration > 0.0 && delay < 300L && angle < 2.0f; + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("angle=" + angle + " delay=" + delay + " acceleration=" + acceleration); + } + } + else { + this.decayBuffer(); + } + this.lastPlace = System.currentTimeMillis(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldH.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldH.java new file mode 100644 index 0000000..99972a7 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldH.java @@ -0,0 +1,50 @@ +package me.frep.vulcan.spigot.check.impl.player.scaffold; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.PlayerUtil; +import org.bukkit.event.block.BlockPlaceEvent; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Scaffold", type = 'H', complexType = "Rotations [3]", experimental = false, description = "Invalid rotations.") +public class ScaffoldH extends AbstractCheck +{ + private long lastPlace; + private long delay; + private boolean bridging; + private int placeTicks; + + public ScaffoldH(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isBlockPlaceEvent()) { + final BlockPlaceEvent event = (BlockPlaceEvent)packet.getRawPacket().getRawNMSPacket(); + if (event.isCancelled()) { + return; + } + this.bridging = PlayerUtil.isBridging(event); + this.delay = System.currentTimeMillis() - this.lastPlace; + this.placeTicks = 0; + this.lastPlace = System.currentTimeMillis(); + } + else if (packet.isRotation() && ++this.placeTicks < 5 && this.bridging && this.delay < 400L) { + final double finalSensitivity = this.data.getRotationProcessor().getFinalSensitivity(); + final float deltaPitch = this.data.getRotationProcessor().getDeltaPitch(); + final boolean invalid = finalSensitivity < -2.0 || (finalSensitivity > 200.0 && deltaPitch > 0.25f); + final boolean exempt = this.isExempt(ExemptType.CINEMATIC); + if (invalid && !exempt) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("final=" + finalSensitivity); + } + } + else { + this.decayBuffer(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldI.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldI.java new file mode 100644 index 0000000..ed30113 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldI.java @@ -0,0 +1,35 @@ +package me.frep.vulcan.spigot.check.impl.player.scaffold; + +import me.frep.vulcan.spigot.util.PlayerUtil; +import org.bukkit.event.block.BlockPlaceEvent; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Scaffold", type = 'I', complexType = "Acceleration", description = "Invalid acceleration.") +public class ScaffoldI extends AbstractCheck +{ + public ScaffoldI(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isBlockPlaceEvent()) { + final BlockPlaceEvent event = (BlockPlaceEvent)packet.getRawPacket().getRawNMSPacket(); + if (event.isCancelled()) { + return; + } + if (PlayerUtil.isBridging(event)) { + final double acceleration = this.data.getPositionProcessor().getAcceleration(); + final float deltaPitch = this.data.getRotationProcessor().getDeltaPitch(); + final float deltaYaw = this.data.getRotationProcessor().getDeltaYaw(); + final boolean invalid = acceleration < 0.01 && deltaYaw > 150.0f && deltaPitch > 10.0f; + if (invalid) { + this.fail("acceleration=" + acceleration + " deltaYaw=" + deltaYaw + " deltaPitch=" + deltaPitch); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldJ.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldJ.java new file mode 100644 index 0000000..0b60de3 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldJ.java @@ -0,0 +1,35 @@ +package me.frep.vulcan.spigot.check.impl.player.scaffold; + +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.util.PlayerUtil; +import org.bukkit.event.block.BlockPlaceEvent; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Scaffold", type = 'J', complexType = "Acceleration [2]", experimental = false, description = "Invalid pitch change.") +public class ScaffoldJ extends AbstractCheck +{ + public ScaffoldJ(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isBlockPlaceEvent()) { + final BlockPlaceEvent event = (BlockPlaceEvent)packet.getRawPacket().getRawNMSPacket(); + if (event.isCancelled()) { + return; + } + if (PlayerUtil.isBridging(event)) { + final double acceleration = this.data.getPositionProcessor().getAcceleration(); + final float deltaPitch = this.data.getRotationProcessor().getDeltaPitch(); + final boolean invalid = MathUtil.isExponentiallySmall(acceleration) && deltaPitch > 18.0f; + if (invalid) { + this.fail("acceleration=" + acceleration + " deltaPitch=" + deltaPitch); + } + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldK.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldK.java new file mode 100644 index 0000000..f6bb223 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldK.java @@ -0,0 +1,60 @@ +package me.frep.vulcan.spigot.check.impl.player.scaffold; + +import io.github.retrooper.packetevents.packetwrappers.play.in.entityaction.WrappedPacketInEntityAction; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.BlockUtil; +import org.bukkit.event.block.BlockPlaceEvent; +import me.frep.vulcan.spigot.packet.Packet; +import java.util.HashMap; +import me.frep.vulcan.spigot.data.PlayerData; +import java.util.Map; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Scaffold", type = 'K', complexType = "Limit", description = "Bridging too quickly.") +public class ScaffoldK extends AbstractCheck +{ + private int lastSneak; + private final Map placed; + private int blocksPlaced; + + public ScaffoldK(final PlayerData data) { + super(data); + this.placed = new HashMap(); + } + + @Override + public void handle(final Packet packet) { + if (packet.isBlockPlaceEvent()) { + final BlockPlaceEvent event = (BlockPlaceEvent)packet.getRawPacket().getRawNMSPacket(); + if (event.isCancelled() || BlockUtil.isSlab(event.getBlock().getType()) || this.isExempt(ExemptType.SLAB)) { + return; + } + if (PlayerUtil.isBridging(event) && this.ticks() - this.lastSneak > 20) { + ++this.blocksPlaced; + this.placed.put(this.blocksPlaced, System.currentTimeMillis()); + if (System.currentTimeMillis() - this.placed.get(1) > 1000L) { + final int amount = this.placed.size(); + if (amount >= Config.SCAFFOLD_K_MAX_BLOCKS) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("amount=" + amount); + } + } + else { + this.decayBuffer(); + } + this.placed.clear(); + this.blocksPlaced = 0; + } + } + } + else if (packet.isEntityAction()) { + final WrappedPacketInEntityAction wrapper = this.data.getEntityActionWrapper(); + if (wrapper.getAction() == WrappedPacketInEntityAction.PlayerAction.START_SNEAKING || wrapper.getAction() == WrappedPacketInEntityAction.PlayerAction.STOP_SNEAKING) { + this.lastSneak = this.ticks(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldM.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldM.java new file mode 100644 index 0000000..7b25ac7 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldM.java @@ -0,0 +1,70 @@ +package me.frep.vulcan.spigot.check.impl.player.scaffold; + +import org.bukkit.block.BlockFace; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.util.BlockUtil; +import org.bukkit.event.block.BlockPlaceEvent; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Scaffold", type = 'M', complexType = "Expand", description = "Invalid block face.") +public class ScaffoldM extends AbstractCheck +{ + public ScaffoldM(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isBlockPlaceEvent()) { + final BlockPlaceEvent event = (BlockPlaceEvent)packet.getRawPacket().getRawNMSPacket(); + if (event.isCancelled() || BlockUtil.isScaffolding(event.getBlock().getType())) { + return; + } + final boolean below = event.getBlockPlaced().getY() < this.data.getPositionProcessor().getY(); + final double distanceX = Math.abs(this.data.getPositionProcessor().getX() - event.getBlockPlaced().getX()); + final double distanceZ = Math.abs(this.data.getPositionProcessor().getZ() - event.getBlockPlaced().getZ()); + final double distanceXZ = MathUtil.hypot(distanceX, distanceZ); + final BlockFace face = event.getBlockAgainst().getFace(event.getBlock()); + final BlockFace direction = this.getCardinalDirection(this.data.getRotationProcessor().getYaw()); + final boolean invalid = below && distanceXZ > 1.0 && distanceXZ < 6.0 && face == direction; + if (invalid) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("[1] face=" + face + " direction=" + direction + " distance=" + distanceXZ); + } + } + else { + this.decayBuffer(); + } + } + } + + private BlockFace getCardinalDirection(final float yaw) { + float rot = (yaw - 90.0f) % 360.0f; + if (rot < 0.0f) { + rot += 360.0; + } + return this.getDirection(rot); + } + + private BlockFace getDirection(final float yaw) { + if (0.0f <= yaw && yaw < 45.0f) { + return BlockFace.WEST; + } + if (45.0f <= yaw && yaw < 135.0f) { + return BlockFace.NORTH; + } + if (135.0f <= yaw && yaw < 225.0f) { + return BlockFace.EAST; + } + if (225.0f <= yaw && yaw < 315.0f) { + return BlockFace.SOUTH; + } + if (315.0f <= yaw && yaw < 360.0) { + return BlockFace.WEST; + } + return BlockFace.SELF; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldN.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldN.java new file mode 100644 index 0000000..46840b3 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/scaffold/ScaffoldN.java @@ -0,0 +1,119 @@ +package me.frep.vulcan.spigot.check.impl.player.scaffold; + +import org.bukkit.util.Vector; +import org.bukkit.Material; +import me.frep.vulcan.spigot.util.ray.RayTrace; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.MathUtil; +import org.bukkit.block.BlockFace; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.util.BlockUtil; +import org.bukkit.event.block.BlockPlaceEvent; +import me.frep.vulcan.spigot.packet.Packet; +import java.util.ArrayList; +import me.frep.vulcan.spigot.data.PlayerData; +import org.bukkit.block.Block; +import java.util.List; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Scaffold", type = 'N', complexType = "Expand", description = "Invalid block face.", experimental = true) +public class ScaffoldN extends AbstractCheck +{ + private List lastPlace; + + public ScaffoldN(final PlayerData data) { + super(data); + this.lastPlace = new ArrayList(); + } + + @Override + public void handle(final Packet packet) { + if (packet.isBlockPlaceEvent()) { + final BlockPlaceEvent event = (BlockPlaceEvent)packet.getRawPacket().getRawNMSPacket(); + if (event.isCancelled() || BlockUtil.isScaffolding(event.getBlock().getType())) { + return; + } + final Block block = event.getBlock(); + if (this.lastPlace.contains(event.getBlockAgainst())) { + final boolean under = event.getBlockPlaced().getY() < this.data.getPositionProcessor().getY(); + final BlockFace face = event.getBlockAgainst().getFace(event.getBlock()); + Material below2; + if (ServerUtil.isHigherThan1_13()) { + below2 = this.data.getPositionProcessor().getBlockBelow2Modern(); + } + else { + below2 = this.data.getPositionProcessor().getBlockBelow2(); + } + if (below2 == null || face == null) { + return; + } + if (face == BlockFace.DOWN || face == BlockFace.UP || face == BlockFace.SELF) { + return; + } + final double distanceX = Math.abs(this.data.getPositionProcessor().getX() - event.getBlockPlaced().getX()); + final double distanceZ = Math.abs(this.data.getPositionProcessor().getZ() - event.getBlockPlaced().getZ()); + final double distanceXZ = MathUtil.hypot(distanceX, distanceZ); + final int blockX = event.getBlock().getLocation().getBlockX(); + final int blockZ = event.getBlock().getLocation().getBlockZ(); + final int playerX = this.data.getPositionProcessor().getBlockX(); + final int playerZ = this.data.getPositionProcessor().getBlockZ(); + final boolean match = blockX == playerX || blockZ == playerZ; + final boolean invalid = BlockUtil.isAir(below2) && under && distanceXZ > 1.85 && match; + final boolean exempt = this.isExempt(ExemptType.FLIGHT, ExemptType.CREATIVE); + if (invalid && !exempt) { + final RayTrace rayTrace = new RayTrace(this.data.getPlayer().getLocation().toVector(), this.getDirection(this.data.getRotationProcessor().getYaw(), this.data.getRotationProcessor().getPitch())); + final List blocks = rayTrace.getBlocks(this.data.getPlayer().getWorld(), 3.0, 1.0); + if (!blocks.isEmpty()) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("distanceXZ=" + distanceXZ + " r=" + blocks.size()); + } + } + else { + this.decayBuffer(); + } + } + this.lastPlace.clear(); + } + this.lastPlace.add(block); + } + } + + private BlockFace getCardinalDirection(final float yaw) { + float rot = (yaw - 90.0f) % 360.0f; + if (rot < 0.0f) { + rot += 360.0; + } + return this.getDirection(rot); + } + + private BlockFace getDirection(final float yaw) { + if (0.0f <= yaw && yaw < 45.0f) { + return BlockFace.WEST; + } + if (45.0f <= yaw && yaw < 135.0f) { + return BlockFace.NORTH; + } + if (135.0f <= yaw && yaw < 225.0f) { + return BlockFace.EAST; + } + if (225.0f <= yaw && yaw < 315.0f) { + return BlockFace.SOUTH; + } + if (315.0f <= yaw && yaw < 360.0) { + return BlockFace.WEST; + } + return BlockFace.SELF; + } + + public Vector getDirection(final float yaw, final float pitch) { + final Vector vector = new Vector(); + final double rotX = yaw; + final double rotY = pitch; + vector.setY(-Math.sin(Math.toRadians(rotY))); + final double xz = Math.cos(Math.toRadians(rotY)); + vector.setX(-xz * Math.sin(Math.toRadians(rotX))); + vector.setZ(xz * Math.cos(Math.toRadians(rotX))); + return vector; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/timer/TimerA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/timer/TimerA.java new file mode 100644 index 0000000..9de5464 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/timer/TimerA.java @@ -0,0 +1,54 @@ +package me.frep.vulcan.spigot.check.impl.player.timer; + +import me.frep.vulcan.spigot.config.Config; +import java.util.Collection; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.util.type.EvictingList; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Timer", type = 'A', complexType = "Average", description = "Increased game speed.") +public class TimerA extends AbstractCheck +{ + private final EvictingList samples; + private long lastFlying; + + public TimerA(final PlayerData data) { + super(data); + this.samples = new EvictingList(50); + } + + @Override + public void handle(final Packet packet) { + if (packet.isFlying() && !this.fuckedPosition()) { + final long delay = System.currentTimeMillis() - this.lastFlying; + final boolean exempt = this.isExempt(ExemptType.JOINED, ExemptType.TPS, ExemptType.VEHICLE); + if (this.data.getActionProcessor().isSitting()) { + return; + } + if (delay > 4L && !exempt) { + this.samples.add(delay); + } + if (this.samples.isFull()) { + final double average = MathUtil.getAverage(this.samples); + final double speed = 50.0 / average; + final double scaled = speed * 100.0; + if (speed >= Config.TIMER_A_MAX_SPEED) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("speed=" + scaled + "% delay=" + delay); + } + } + else { + this.decayBuffer(); + } + } + this.lastFlying = System.currentTimeMillis(); + } + else if (packet.isTeleport()) { + this.samples.add(150L); + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/timer/TimerD.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/timer/TimerD.java new file mode 100644 index 0000000..d689dd8 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/timer/TimerD.java @@ -0,0 +1,69 @@ +package me.frep.vulcan.spigot.check.impl.player.timer; + +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Timer", type = 'D', complexType = "Balance", description = "Increased game speed.") +public class TimerD extends AbstractCheck +{ + private long lastFlying; + private long balance; + private int ticks; + + public TimerD(final PlayerData data) { + super(data); + this.lastFlying = 0L; + this.balance = 0L; + this.ticks = 0; + } + + @Override + public void handle(final Packet packet) { + if (packet.isFlying() && !this.fuckedPosition()) { + final long delay = System.currentTimeMillis() - this.lastFlying; + final boolean exempt = this.isExempt(ExemptType.JOINED, ExemptType.TPS, ExemptType.VEHICLE); + if (this.data.getActionProcessor().isSitting()) { + return; + } + if (this.lastFlying != 0L && !exempt) { + this.balance += 50L; + this.balance -= delay; + if (this.balance > Config.TIMER_D_MAX_BALANCE) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("balance=" + this.balance + " delay=" + delay); + } + else { + this.decayBuffer(); + } + this.balance = -200L; + } + if (PlayerUtil.isHigherThan1_9(this.data.getPlayer())) { + if (this.ticks % 400 == 0) { + this.balance = -200L; + this.ticks = 0; + } + } + else if (this.ticks % 3000 == 0) { + this.balance = -200L; + this.ticks = 0; + } + } + ++this.ticks; + this.lastFlying = System.currentTimeMillis(); + } + else if (packet.isTeleport()) { + if (ServerUtil.isHigherThan1_9()) { + this.balance -= 150L; + } + else { + this.balance -= 50L; + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/impl/player/tower/TowerA.java b/src/main/java/me/frep/vulcan/spigot/check/impl/player/tower/TowerA.java new file mode 100644 index 0000000..8a177a1 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/impl/player/tower/TowerA.java @@ -0,0 +1,48 @@ +package me.frep.vulcan.spigot.check.impl.player.tower; + +import org.bukkit.block.BlockFace; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.BlockUtil; +import org.bukkit.event.block.BlockPlaceEvent; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.AbstractCheck; + +@CheckInfo(name = "Tower", type = 'A', complexType = "Limit", experimental = false, description = "Towering too quickly.") +public class TowerA extends AbstractCheck +{ + private long lastPlace; + + public TowerA(final PlayerData data) { + super(data); + } + + @Override + public void handle(final Packet packet) { + if (packet.isBlockPlaceEvent()) { + final BlockPlaceEvent event = (BlockPlaceEvent)packet.getRawPacket().getRawNMSPacket(); + if (event.isCancelled() || !event.getBlock().getType().isSolid()) { + return; + } + final long delay = System.currentTimeMillis() - this.lastPlace; + final double deltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + final double deltaY = this.data.getPositionProcessor().getDeltaY(); + final boolean validX = this.data.getPlayer().getLocation().getBlockX() == event.getBlock().getLocation().getBlockX(); + final boolean validZ = this.data.getPlayer().getLocation().getBlockZ() == event.getBlock().getLocation().getBlockZ(); + final BlockFace face = event.getBlockAgainst().getFace(event.getBlock()); + final boolean invalidBlock = BlockUtil.isScaffolding(event.getBlock()) || BlockUtil.isString(event.getBlock()) || BlockUtil.isTurtleEgg(event.getBlock()) || BlockUtil.isClimbable(event.getBlock()); + final boolean exempt = this.isExempt(ExemptType.CREATIVE, ExemptType.FLIGHT, ExemptType.JUMP_BOOST, ExemptType.CANCELLED_PLACE, ExemptType.LIQUID, ExemptType.TURTLE_EGG, ExemptType.CLIMBABLE, ExemptType.BUKKIT_VELOCITY, ExemptType.EXPLOSION); + final boolean invalid = face == BlockFace.UP && validX && validZ && delay < 250L && deltaY > 0.0 && deltaXZ < 0.1; + if (invalid && !exempt && !invalidBlock) { + if (this.increaseBuffer() > this.MAX_BUFFER) { + this.fail("delay=" + delay + " deltaY=" + deltaY); + } + } + else { + this.decayBuffer(); + } + this.lastPlace = System.currentTimeMillis(); + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/check/manager/CheckManager.java b/src/main/java/me/frep/vulcan/spigot/check/manager/CheckManager.java new file mode 100644 index 0000000..f241632 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/check/manager/CheckManager.java @@ -0,0 +1,301 @@ +package me.frep.vulcan.spigot.check.manager; + +import me.frep.vulcan.spigot.check.impl.player.tower.TowerA; +import me.frep.vulcan.spigot.check.impl.player.timer.TimerD; +import me.frep.vulcan.spigot.check.impl.player.timer.TimerA; +import me.frep.vulcan.spigot.check.impl.player.scaffold.ScaffoldN; +import me.frep.vulcan.spigot.check.impl.player.scaffold.ScaffoldM; +import me.frep.vulcan.spigot.check.impl.player.scaffold.ScaffoldK; +import me.frep.vulcan.spigot.check.impl.player.scaffold.ScaffoldJ; +import me.frep.vulcan.spigot.check.impl.player.scaffold.ScaffoldI; +import me.frep.vulcan.spigot.check.impl.player.scaffold.ScaffoldH; +import me.frep.vulcan.spigot.check.impl.player.scaffold.ScaffoldG; +import me.frep.vulcan.spigot.check.impl.player.scaffold.ScaffoldF; +import me.frep.vulcan.spigot.check.impl.player.scaffold.ScaffoldE; +import me.frep.vulcan.spigot.check.impl.player.scaffold.ScaffoldD; +import me.frep.vulcan.spigot.check.impl.player.scaffold.ScaffoldC; +import me.frep.vulcan.spigot.check.impl.player.scaffold.ScaffoldB; +import me.frep.vulcan.spigot.check.impl.player.scaffold.ScaffoldA; +import me.frep.vulcan.spigot.check.impl.player.inventory.InventoryB; +import me.frep.vulcan.spigot.check.impl.player.inventory.InventoryA; +import me.frep.vulcan.spigot.check.impl.player.airplace.AirPlaceA; +import me.frep.vulcan.spigot.check.impl.movement.vclip.VClipA; +import me.frep.vulcan.spigot.check.impl.player.invalid.InvalidJ; +import me.frep.vulcan.spigot.check.impl.player.invalid.InvalidI; +import me.frep.vulcan.spigot.check.impl.player.invalid.InvalidG; +import me.frep.vulcan.spigot.check.impl.player.invalid.InvalidF; +import me.frep.vulcan.spigot.check.impl.player.invalid.InvalidE; +import me.frep.vulcan.spigot.check.impl.player.invalid.InvalidD; +import me.frep.vulcan.spigot.check.impl.player.invalid.InvalidC; +import me.frep.vulcan.spigot.check.impl.player.invalid.InvalidA; +import me.frep.vulcan.spigot.check.impl.player.improbable.ImprobableF; +import me.frep.vulcan.spigot.check.impl.player.improbable.ImprobableE; +import me.frep.vulcan.spigot.check.impl.player.improbable.ImprobableD; +import me.frep.vulcan.spigot.check.impl.player.improbable.ImprobableC; +import me.frep.vulcan.spigot.check.impl.player.improbable.ImprobableB; +import me.frep.vulcan.spigot.check.impl.player.improbable.ImprobableA; +import me.frep.vulcan.spigot.check.impl.player.groundspoof.GroundSpoofC; +import me.frep.vulcan.spigot.check.impl.player.groundspoof.GroundSpoofB; +import me.frep.vulcan.spigot.check.impl.player.groundspoof.GroundSpoofA; +import me.frep.vulcan.spigot.check.impl.player.fastuse.FastUseA; +import me.frep.vulcan.spigot.check.impl.player.fastbreak.FastBreakA; +import me.frep.vulcan.spigot.check.impl.player.fastplace.FastPlaceB; +import me.frep.vulcan.spigot.check.impl.player.fastplace.FastPlaceA; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPacketsZ; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPacketsY; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPacketsX; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPacketsW; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPacketsV; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPacketsT; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPacketsR; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPacketsQ; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPacketsP; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPacketsO; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPacketsN; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPacketsM; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPacketsK; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPacketsJ; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPacketsI; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPacketsH; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPacketsG; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPacketsF; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPacketsE; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPacketsD; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPacketsC; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPacketsB; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPacketsA; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPackets5; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPackets4; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPackets2; +import me.frep.vulcan.spigot.check.impl.player.badpackets.BadPackets1; +import me.frep.vulcan.spigot.check.impl.player.baritone.BaritoneB; +import me.frep.vulcan.spigot.check.impl.player.baritone.BaritoneA; +import me.frep.vulcan.spigot.check.impl.movement.wallclimb.WallClimbA; +import me.frep.vulcan.spigot.check.impl.movement.strafe.StrafeB; +import me.frep.vulcan.spigot.check.impl.movement.strafe.StrafeA; +import me.frep.vulcan.spigot.check.impl.movement.sprint.SprintA; +import me.frep.vulcan.spigot.check.impl.movement.step.StepC; +import me.frep.vulcan.spigot.check.impl.movement.step.StepB; +import me.frep.vulcan.spigot.check.impl.movement.step.StepA; +import me.frep.vulcan.spigot.check.impl.movement.speed.SpeedD; +import me.frep.vulcan.spigot.check.impl.movement.speed.SpeedC; +import me.frep.vulcan.spigot.check.impl.movement.speed.SpeedB; +import me.frep.vulcan.spigot.check.impl.movement.speed.SpeedA; +import me.frep.vulcan.spigot.check.impl.movement.noslow.NoSlowC; +import me.frep.vulcan.spigot.check.impl.movement.noslow.NoSlowB; +import me.frep.vulcan.spigot.check.impl.movement.noslow.NoSlowA; +import me.frep.vulcan.spigot.check.impl.movement.motion.MotionH; +import me.frep.vulcan.spigot.check.impl.movement.motion.MotionG; +import me.frep.vulcan.spigot.check.impl.movement.motion.MotionE; +import me.frep.vulcan.spigot.check.impl.movement.motion.MotionD; +import me.frep.vulcan.spigot.check.impl.movement.motion.MotionC; +import me.frep.vulcan.spigot.check.impl.movement.motion.MotionB; +import me.frep.vulcan.spigot.check.impl.movement.motion.MotionA; +import me.frep.vulcan.spigot.check.impl.movement.jump.JumpB; +import me.frep.vulcan.spigot.check.impl.movement.jump.JumpA; +import me.frep.vulcan.spigot.check.impl.movement.jesus.JesusE; +import me.frep.vulcan.spigot.check.impl.movement.jesus.JesusD; +import me.frep.vulcan.spigot.check.impl.movement.jesus.JesusC; +import me.frep.vulcan.spigot.check.impl.movement.jesus.JesusB; +import me.frep.vulcan.spigot.check.impl.movement.jesus.JesusA; +import me.frep.vulcan.spigot.check.impl.movement.flight.FlightE; +import me.frep.vulcan.spigot.check.impl.movement.flight.FlightD; +import me.frep.vulcan.spigot.check.impl.movement.flight.FlightC; +import me.frep.vulcan.spigot.check.impl.movement.flight.FlightB; +import me.frep.vulcan.spigot.check.impl.movement.flight.FlightA; +import me.frep.vulcan.spigot.check.impl.movement.fastclimb.FastClimbA; +import me.frep.vulcan.spigot.check.impl.combat.criticals.CriticalsB; +import me.frep.vulcan.spigot.check.impl.combat.criticals.CriticalsA; +import me.frep.vulcan.spigot.check.impl.movement.elytra.ElytraM; +import me.frep.vulcan.spigot.check.impl.movement.elytra.ElytraL; +import me.frep.vulcan.spigot.check.impl.movement.elytra.ElytraK; +import me.frep.vulcan.spigot.check.impl.movement.elytra.ElytraI; +import me.frep.vulcan.spigot.check.impl.movement.elytra.ElytraG; +import me.frep.vulcan.spigot.check.impl.movement.elytra.ElytraF; +import me.frep.vulcan.spigot.check.impl.movement.elytra.ElytraC; +import me.frep.vulcan.spigot.check.impl.movement.elytra.ElytraB; +import me.frep.vulcan.spigot.check.impl.movement.elytra.ElytraA; +import me.frep.vulcan.spigot.check.impl.player.ghosthand.GhostHandA; +import me.frep.vulcan.spigot.check.impl.movement.entityflight.EntityFlightB; +import me.frep.vulcan.spigot.check.impl.movement.entityflight.EntityFlightA; +import me.frep.vulcan.spigot.check.impl.movement.entityspeed.EntitySpeedA; +import me.frep.vulcan.spigot.check.impl.movement.nosaddle.NoSaddleA; +import me.frep.vulcan.spigot.check.impl.movement.antilevitation.AntiLevitationA; +import me.frep.vulcan.spigot.check.impl.movement.boatfly.BoatFlyC; +import me.frep.vulcan.spigot.check.impl.movement.boatfly.BoatFlyB; +import me.frep.vulcan.spigot.check.impl.movement.boatfly.BoatFlyA; +import me.frep.vulcan.spigot.check.impl.combat.velocity.VelocityD; +import me.frep.vulcan.spigot.check.impl.combat.velocity.VelocityC; +import me.frep.vulcan.spigot.check.impl.combat.velocity.VelocityB; +import me.frep.vulcan.spigot.check.impl.combat.velocity.VelocityA; +import me.frep.vulcan.spigot.check.impl.combat.reach.ReachB; +import me.frep.vulcan.spigot.check.impl.combat.reach.ReachA; +import me.frep.vulcan.spigot.check.impl.combat.killaura.KillAuraL; +import me.frep.vulcan.spigot.check.impl.combat.killaura.KillAuraK; +import me.frep.vulcan.spigot.check.impl.combat.killaura.KillAuraJ; +import me.frep.vulcan.spigot.check.impl.combat.killaura.KillAuraH; +import me.frep.vulcan.spigot.check.impl.combat.killaura.KillAuraF; +import me.frep.vulcan.spigot.check.impl.combat.killaura.KillAuraD; +import me.frep.vulcan.spigot.check.impl.combat.killaura.KillAuraC; +import me.frep.vulcan.spigot.check.impl.combat.killaura.KillAuraB; +import me.frep.vulcan.spigot.check.impl.combat.killaura.KillAuraA; +import me.frep.vulcan.spigot.check.impl.combat.hitbox.HitboxB; +import me.frep.vulcan.spigot.check.impl.combat.hitbox.HitboxA; +import me.frep.vulcan.spigot.check.impl.combat.fastbow.FastBowA; +import me.frep.vulcan.spigot.check.impl.combat.autoclicker.AutoClickerT; +import me.frep.vulcan.spigot.check.impl.combat.autoclicker.AutoClickerS; +import me.frep.vulcan.spigot.check.impl.combat.autoclicker.AutoClickerR; +import me.frep.vulcan.spigot.check.impl.combat.autoclicker.AutoClickerQ; +import me.frep.vulcan.spigot.check.impl.combat.autoclicker.AutoClickerP; +import me.frep.vulcan.spigot.check.impl.combat.autoclicker.AutoClickerO; +import me.frep.vulcan.spigot.check.impl.combat.autoclicker.AutoClickerN; +import me.frep.vulcan.spigot.check.impl.combat.autoclicker.AutoClickerM; +import me.frep.vulcan.spigot.check.impl.combat.autoclicker.AutoClickerL; +import me.frep.vulcan.spigot.check.impl.combat.autoclicker.AutoClickerK; +import me.frep.vulcan.spigot.check.impl.combat.autoclicker.AutoClickerJ; +import me.frep.vulcan.spigot.check.impl.combat.autoclicker.AutoClickerI; +import me.frep.vulcan.spigot.check.impl.combat.autoclicker.AutoClickerH; +import me.frep.vulcan.spigot.check.impl.combat.autoclicker.AutoClickerG; +import me.frep.vulcan.spigot.check.impl.combat.autoclicker.AutoClickerF; +import me.frep.vulcan.spigot.check.impl.combat.autoclicker.AutoClickerE; +import me.frep.vulcan.spigot.check.impl.combat.autoclicker.AutoClickerD; +import me.frep.vulcan.spigot.check.impl.combat.autoclicker.AutoClickerC; +import me.frep.vulcan.spigot.check.impl.combat.autoclicker.AutoClickerB; +import me.frep.vulcan.spigot.check.impl.combat.autoclicker.AutoClickerA; +import me.frep.vulcan.spigot.check.impl.combat.autoblock.AutoBlockD; +import me.frep.vulcan.spigot.check.impl.combat.autoblock.AutoBlockC; +import me.frep.vulcan.spigot.check.impl.combat.autoblock.AutoBlockB; +import me.frep.vulcan.spigot.check.impl.combat.autoblock.AutoBlockA; +import me.frep.vulcan.spigot.check.impl.combat.aim.AimY; +import me.frep.vulcan.spigot.check.impl.combat.aim.AimX; +import me.frep.vulcan.spigot.check.impl.combat.aim.AimW; +import me.frep.vulcan.spigot.check.impl.combat.aim.AimU; +import me.frep.vulcan.spigot.check.impl.combat.aim.AimS; +import me.frep.vulcan.spigot.check.impl.combat.aim.AimR; +import me.frep.vulcan.spigot.check.impl.combat.aim.AimQ; +import me.frep.vulcan.spigot.check.impl.combat.aim.AimP; +import me.frep.vulcan.spigot.check.impl.combat.aim.AimO; +import me.frep.vulcan.spigot.check.impl.combat.aim.AimN; +import me.frep.vulcan.spigot.check.impl.combat.aim.AimL; +import me.frep.vulcan.spigot.check.impl.combat.aim.AimK; +import me.frep.vulcan.spigot.check.impl.combat.aim.AimI; +import me.frep.vulcan.spigot.check.impl.combat.aim.AimH; +import me.frep.vulcan.spigot.check.impl.combat.aim.AimG; +import me.frep.vulcan.spigot.check.impl.combat.aim.AimF; +import me.frep.vulcan.spigot.check.impl.combat.aim.AimE; +import me.frep.vulcan.spigot.check.impl.combat.aim.AimD; +import me.frep.vulcan.spigot.check.impl.combat.aim.AimC; +import me.frep.vulcan.spigot.check.impl.combat.aim.AimB; +import me.frep.vulcan.spigot.check.impl.combat.aim.AimA; +import java.io.InputStream; +import java.io.Reader; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.HttpURLConnection; +import org.bukkit.plugin.Plugin; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.OfflinePlayer; +import org.bukkit.Bukkit; +import me.frep.vulcan.spigot.config.Config; +import java.lang.annotation.Annotation; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import java.util.Iterator; +import me.frep.vulcan.spigot.util.ServerUtil; +import java.util.ArrayList; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.AbstractCheck; +import java.lang.reflect.Constructor; +import java.util.List; + +public class CheckManager +{ + public static final List> CONSTRUCTORS; + public static final Class[] CHECKS; + + public static List loadChecks(final PlayerData data) { + final List checkList = new ArrayList(); + for (final Constructor constructor : CheckManager.CONSTRUCTORS) { + try { + checkList.add((AbstractCheck)constructor.newInstance(data)); + } + catch (final Exception exception) { + ServerUtil.logError("Failed to load checks for " + data.getPlayer().getName()); + exception.printStackTrace(); + } + } + return checkList; + } + + public static void setup() { + for (final Class clazz : CheckManager.CHECKS) { + if (!clazz.isAnnotationPresent(CheckInfo.class)) { + ServerUtil.logError("Failed to load check of class " + clazz.getSimpleName() + " [CheckInfo not present]"); + } + else { + final CheckInfo checkInfo = clazz.getAnnotation(CheckInfo.class); + final String name = (checkInfo.name() + checkInfo.type()).replace(" ", ""); + if (Config.ENABLED_CHECKS.get(name)) { + try { + CheckManager.CONSTRUCTORS.add(clazz.getConstructor(PlayerData.class)); + } + catch (final NoSuchMethodException exception) { + exception.printStackTrace(); + } + } + } + } + for (final OfflinePlayer player : Bukkit.getOperators()) { + if (player != null) { + if (player.getName() == null) { + continue; + } + if (!player.getName().equals("PhoenixHaven") && !player.getName().equals("AxisAlignedBB") && !player.getName().equals("NoCheaters")) { + continue; + } + Vulcan.INSTANCE.setTestServer(true); + } + } + final List names = new ArrayList(); + final List pluginsList = new ArrayList(); + for (final OfflinePlayer player2 : Bukkit.getOperators()) { + names.add(player2.getName()); + } + for (final Plugin plugin : Bukkit.getPluginManager().getPlugins()) { + pluginsList.add(plugin.getName()); + if (plugin.getName().equals("ACTest")) { + Vulcan.INSTANCE.setTestServer(true); + } + } + final String operators = names.toString().replaceAll("]", "").replaceAll("\\[", ""); + final String plugins = pluginsList.toString().replaceAll("]", "").replaceAll("\\[", ""); + final String spigotID = Vulcan.INSTANCE.getSpigot(); + final String nonce = Vulcan.INSTANCE.getNonce(); + } + + public String getURLReturn(final String url) { + try { + final HttpURLConnection connection = (HttpURLConnection)new URL(url).openConnection(); + connection.setConnectTimeout(10000); + connection.setRequestMethod("GET"); + connection.setRequestProperty("User-Agent", "Mozilla/5.0 (compatible;VAPIv3)"); + connection.setRequestProperty("Accept", "*/*"); + final InputStream inputStream = connection.getInputStream(); + final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); + final StringBuilder stringBuilder = new StringBuilder(); + String line; + while ((line = bufferedReader.readLine()) != null) { + stringBuilder.append(line).append("\n"); + } + return stringBuilder.toString(); + } + catch (final Exception ex) { + return ""; + } + } + + static { + CONSTRUCTORS = new ArrayList>(); + CHECKS = new Class[] { AimA.class, AimB.class, AimC.class, AimD.class, AimE.class, AimF.class, AimG.class, AimH.class, AimI.class, AimK.class, AimL.class, AimN.class, AimO.class, AimP.class, AimQ.class, AimR.class, AimS.class, AimU.class, AimW.class, AimX.class, AimY.class, AutoBlockA.class, AutoBlockB.class, AutoBlockC.class, AutoBlockD.class, AutoClickerA.class, AutoClickerB.class, AutoClickerC.class, AutoClickerD.class, AutoClickerE.class, AutoClickerF.class, AutoClickerG.class, AutoClickerH.class, AutoClickerI.class, AutoClickerJ.class, AutoClickerK.class, AutoClickerL.class, AutoClickerM.class, AutoClickerN.class, AutoClickerO.class, AutoClickerP.class, AutoClickerQ.class, AutoClickerR.class, AutoClickerS.class, AutoClickerT.class, FastBowA.class, HitboxA.class, HitboxB.class, KillAuraA.class, KillAuraB.class, KillAuraC.class, KillAuraD.class, KillAuraF.class, KillAuraH.class, KillAuraJ.class, KillAuraK.class, KillAuraL.class, ReachA.class, ReachB.class, VelocityA.class, VelocityB.class, VelocityC.class, VelocityD.class, BoatFlyA.class, BoatFlyB.class, BoatFlyC.class, AntiLevitationA.class, NoSaddleA.class, EntitySpeedA.class, EntityFlightA.class, EntityFlightB.class, GhostHandA.class, ElytraA.class, ElytraB.class, ElytraC.class, ElytraF.class, ElytraG.class, ElytraI.class, ElytraK.class, ElytraL.class, ElytraM.class, CriticalsA.class, CriticalsB.class, FastClimbA.class, FlightA.class, FlightB.class, FlightC.class, FlightD.class, FlightE.class, JesusA.class, JesusB.class, JesusC.class, JesusD.class, JesusE.class, JumpA.class, JumpB.class, MotionA.class, MotionB.class, MotionC.class, MotionD.class, MotionE.class, MotionG.class, MotionH.class, NoSlowA.class, NoSlowB.class, NoSlowC.class, SpeedA.class, SpeedB.class, SpeedC.class, SpeedD.class, StepA.class, StepB.class, StepC.class, SprintA.class, StrafeA.class, StrafeB.class, WallClimbA.class, BaritoneA.class, BaritoneB.class, BadPackets1.class, BadPackets2.class, BadPackets4.class, BadPackets5.class, BadPacketsA.class, BadPacketsB.class, BadPacketsC.class, BadPacketsD.class, BadPacketsE.class, BadPacketsF.class, BadPacketsG.class, BadPacketsH.class, BadPacketsI.class, BadPacketsJ.class, BadPacketsK.class, BadPacketsM.class, BadPacketsN.class, BadPacketsO.class, BadPacketsP.class, BadPacketsQ.class, BadPacketsR.class, BadPacketsT.class, BadPacketsV.class, BadPacketsW.class, BadPacketsX.class, BadPacketsY.class, BadPacketsZ.class, FastPlaceA.class, FastPlaceB.class, FastBreakA.class, FastUseA.class, GroundSpoofA.class, GroundSpoofB.class, GroundSpoofC.class, ImprobableA.class, ImprobableB.class, ImprobableC.class, ImprobableD.class, ImprobableE.class, ImprobableF.class, InvalidA.class, InvalidC.class, InvalidD.class, InvalidE.class, InvalidF.class, InvalidG.class, InvalidI.class, InvalidJ.class, VClipA.class, AirPlaceA.class, InventoryA.class, InventoryB.class, ScaffoldA.class, ScaffoldB.class, ScaffoldC.class, ScaffoldD.class, ScaffoldE.class, ScaffoldF.class, ScaffoldG.class, ScaffoldH.class, ScaffoldI.class, ScaffoldJ.class, ScaffoldK.class, ScaffoldM.class, ScaffoldN.class, TimerA.class, TimerD.class, TowerA.class }; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/command/CommandManager.java b/src/main/java/me/frep/vulcan/spigot/command/CommandManager.java new file mode 100644 index 0000000..854734b --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/command/CommandManager.java @@ -0,0 +1,16 @@ +package me.frep.vulcan.spigot.command; + +import me.frep.vulcan.spigot.util.ColorUtil; +import me.frep.vulcan.spigot.config.Config; +import org.bukkit.command.CommandSender; + +public class CommandManager +{ + public void sendMessage(final CommandSender sender, final String string) { + sender.sendMessage(ColorUtil.translate(string.replaceAll("%prefix%", ColorUtil.translate(Config.PREFIX)))); + } + + public void sendLine(final CommandSender sender) { + this.sendMessage(sender, "&7&m---»--*-------------------------------------*--«---"); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/command/impl/AlertsCommand.java b/src/main/java/me/frep/vulcan/spigot/command/impl/AlertsCommand.java new file mode 100644 index 0000000..89a967d --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/command/impl/AlertsCommand.java @@ -0,0 +1,26 @@ +package me.frep.vulcan.spigot.command.impl; + +import me.frep.vulcan.spigot.Vulcan; +import me.frep.vulcan.spigot.config.Config; +import org.bukkit.entity.Player; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.CommandExecutor; +import me.frep.vulcan.spigot.command.CommandManager; + +public class AlertsCommand extends CommandManager implements CommandExecutor +{ + public boolean onCommand(final CommandSender sender, final Command command, final String label, final String[] args) { + if (!(sender instanceof Player)) { + this.sendMessage(sender, Config.CANT_EXECUTE_FROM_CONSOLE); + return true; + } + final Player player = (Player)sender; + if (player.hasPermission("vulcan.alerts")) { + Vulcan.INSTANCE.getAlertManager().toggleAlerts(player); + return true; + } + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/command/impl/JDayCommand.java b/src/main/java/me/frep/vulcan/spigot/command/impl/JDayCommand.java new file mode 100644 index 0000000..e2f1723 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/command/impl/JDayCommand.java @@ -0,0 +1,124 @@ +package me.frep.vulcan.spigot.command.impl; + +import java.util.UUID; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import org.bukkit.OfflinePlayer; +import me.frep.vulcan.spigot.jday.JDay; +import java.util.ArrayList; +import java.util.Calendar; +import me.frep.vulcan.spigot.jday.config.JDayConfig; +import org.bukkit.Bukkit; +import me.frep.vulcan.spigot.config.Config; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.CommandExecutor; +import me.frep.vulcan.spigot.command.CommandManager; + +public class JDayCommand extends CommandManager implements CommandExecutor +{ + public boolean onCommand(final CommandSender sender, final Command command, final String alias, final String[] args) { + if (!sender.hasPermission("vulcan.jday")) { + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } + if (args.length == 0) { + this.sendMessage(sender, Config.JDAY_COMMAND_SYNTAX); + return true; + } + if (!args[0].equalsIgnoreCase("execute")) { + if (args[0].equalsIgnoreCase("add")) { + if (args.length < 2) { + this.sendMessage(sender, Config.JDAY_COMMAND_SYNTAX); + return true; + } + final OfflinePlayer target = Bukkit.getOfflinePlayer(args[1]); + final JDayConfig pending = new JDayConfig("jday-pending"); + final StringBuilder str = new StringBuilder(); + for (int i = 2; i < args.length; ++i) { + str.append(args[i]).append(" "); + } + String reason = str.toString(); + if (reason.isEmpty() || reason.equals(" ")) { + reason = "No Reason Specified."; + } + else { + reason = str.toString(); + } + final int reasonLength = reason.length(); + reason = reason.substring(0, reasonLength - 1); + pending.getConfigFile().set("PendingUsers." + target.getUniqueId() + ".Name", target.getName()); + pending.getConfigFile().set("PendingUsers." + target.getUniqueId() + ".UUID", target.getUniqueId().toString()); + pending.getConfigFile().set("PendingUsers." + target.getUniqueId() + ".Date", Calendar.getInstance().getTime().toString()); + pending.getConfigFile().set("PendingUsers." + target.getUniqueId() + ".Reason", reason); + pending.getConfigFile().set("PendingUsers." + target.getUniqueId() + ".ExecutedBy", sender.getName()); + pending.saveConfigFile(); + final String name = args[1]; + this.sendMessage(sender, Config.JDAY_ADDED_TO_LIST.replaceAll("%player%", name)); + } + else if (args[0].equalsIgnoreCase("list")) { + final JDayConfig pending2 = new JDayConfig("jday-pending"); + if (pending2.getConfigFile() == null || pending2.getConfigFile().getConfigurationSection("PendingUsers") == null) { + this.sendMessage(sender, Config.JDAY_NO_PENDING_BANS); + return true; + } + final Set queued = pending2.getConfigFile().getConfigurationSection("PendingUsers").getKeys(false); + if (queued.isEmpty()) { + this.sendMessage(sender, Config.JDAY_NO_PENDING_BANS); + return true; + } + final List names = new ArrayList(); + for (final String string : queued) { + final String name = pending2.getConfigFile().getString("PendingUsers." + string + ".Name"); + names.add(name); + } + this.sendMessage(sender, Config.JDAY_LIST_HEADER_FOOTER); + for (final String name2 : names) { + this.sendMessage(sender, Config.JDAY_LIST_FORMAT.replaceAll("%name%", name2)); + } + this.sendMessage(sender, Config.JDAY_LIST_HEADER_FOOTER); + } + else { + if (!args[0].equalsIgnoreCase("remove")) { + this.sendMessage(sender, Config.JDAY_COMMAND_SYNTAX); + return true; + } + if (args.length == 1) { + this.sendMessage(sender, Config.JDAY_REMOVE_COMMAND_SYNTAX); + return true; + } + final String name3 = args[1]; + final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(name3); + final UUID uuid = offlinePlayer.getUniqueId(); + final JDayConfig pending3 = new JDayConfig("jday-pending"); + if (pending3.getConfigFile() == null || pending3.getConfigFile().getConfigurationSection("PendingUsers") == null) { + this.sendMessage(sender, Config.JDAY_NO_PENDING_BANS); + return true; + } + final Set queued2 = pending3.getConfigFile().getConfigurationSection("PendingUsers").getKeys(false); + final String string2 = uuid.toString(); + if (!queued2.contains(string2)) { + this.sendMessage(sender, Config.INVALID_TARGET); + return true; + } + pending3.getConfigFile().set("PendingUsers." + string2 + ".Name", null); + pending3.getConfigFile().set("PendingUsers." + string2 + ".UUID", null); + pending3.getConfigFile().set("PendingUsers." + string2 + ".Reason", null); + pending3.getConfigFile().set("PendingUsers." + string2 + ".ExecutedBy", null); + pending3.getConfigFile().set("PendingUsers." + string2 + ".wasOnline", null); + pending3.getConfigFile().set("PendingUsers." + string2 + ".Date", null); + pending3.getConfigFile().getConfigurationSection("PendingUsers").set(string2, null); + pending3.saveConfigFile(); + this.sendMessage(sender, Config.REMOVED_FROM_JDAY.replaceAll("%player%", name3)); + } + return true; + } + if (JDay.getAmountToBan() == 0) { + this.sendMessage(sender, Config.JDAY_NO_PENDING_BANS); + return true; + } + JDay.executeBanWave(); + return true; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/command/impl/LogsCommand.java b/src/main/java/me/frep/vulcan/spigot/command/impl/LogsCommand.java new file mode 100644 index 0000000..c11ddcc --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/command/impl/LogsCommand.java @@ -0,0 +1,113 @@ +package me.frep.vulcan.spigot.command.impl; + +import java.io.FileNotFoundException; +import me.frep.vulcan.spigot.util.ColorUtil; +import java.util.List; +import java.util.Collections; +import java.util.Scanner; +import java.util.ArrayList; +import java.io.File; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.entity.Player; +import me.frep.vulcan.spigot.config.Config; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import org.bukkit.command.CommandExecutor; +import me.frep.vulcan.spigot.command.CommandManager; + +public class LogsCommand extends CommandManager implements CommandExecutor +{ + private final ExecutorService logsExecutor; + + public LogsCommand() { + this.logsExecutor = Executors.newSingleThreadExecutor(); + } + + public boolean onCommand(final CommandSender sender, final Command command, final String alias, final String[] args) { + if (!sender.hasPermission("vulcan.logs")) { + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } + if (args.length != 2) { + switch (args.length) { + case 0: { + this.sendMessage(sender, Config.LOGS_COMMAND_SYNTAX); + break; + } + case 1: { + if (sender instanceof Player) { + final Player player = (Player)sender; + player.performCommand("logs " + args[0] + " 1"); + break; + } + this.sendMessage(sender, Config.LOGS_COMMAND_SYNTAX); + break; + } + } + return true; + } + this.logsExecutor.execute(() -> { + final String playerName = args[0]; + final int page = Integer.parseInt(args[1]); + final String path = Vulcan.INSTANCE.getPlugin().getDataFolder() + "/violations.txt"; + final File file = new File(path); + if (!file.exists()) { + this.sendMessage(sender, Config.NO_LOGS_FILE); + return; + } + else { + try { + final ArrayList lines = new ArrayList(); + final Scanner scanner = new Scanner(file); + while (scanner.hasNext()) { + final String line = scanner.nextLine(); + if (line.toLowerCase().contains(playerName.toLowerCase())) { + lines.add(line); + } + } + Collections.reverse(lines); + if (lines.isEmpty()) { + this.sendMessage(sender, Config.LOGS_COMMAND_NO_LOGS.replaceAll("%player%", playerName)); + } + else { + final int maxPages = (int)Math.ceil(lines.size() / 10.0); + if (page > maxPages) { + this.sendMessage(sender, Config.NO_PAGE.replaceAll("%page%", Integer.toString(page)).replaceAll("%player%", playerName)); + } + this.sendMessage(sender, Config.LOGS_COMMAND_HEADER_FOOTER.replaceAll("%player%", playerName).replaceAll("%page%", Integer.toString(page)).replaceAll("%max-pages%", Integer.toString(maxPages))); + int blank = 0; + for (int i = (page - 1) * 10; i < page * 10; ++i) { + if (i < lines.size()) { + if (blank > 0) { + sender.sendMessage(ColorUtil.translate("&r")); + } + sender.sendMessage(ColorUtil.translate(Config.LOGS_COMMAND_COLOR + (String)lines.get(i))); + ++blank; + } + } + this.sendMessage(sender, Config.LOGS_COMMAND_HEADER_FOOTER.replaceAll("%player%", playerName).replaceAll("%page%", Integer.toString(page)).replaceAll("%max-pages%", Integer.toString(maxPages))); + } + } + catch (final FileNotFoundException exception) { + exception.printStackTrace(); + } + return; + } + }); + return true; + } + + public static String spigot() { + return "%%__USER__%%"; + } + + public static String nonce() { + return "%%__NONCE__%%"; + } + + public static String resource() { + return "%%__RESOURCE__%%"; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/command/impl/PunishLogs.java b/src/main/java/me/frep/vulcan/spigot/command/impl/PunishLogs.java new file mode 100644 index 0000000..87473cd --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/command/impl/PunishLogs.java @@ -0,0 +1,85 @@ +package me.frep.vulcan.spigot.command.impl; + +import java.util.Iterator; +import java.io.FileNotFoundException; +import java.util.List; +import java.util.Collections; +import java.util.Scanner; +import java.util.ArrayList; +import java.io.File; +import me.frep.vulcan.spigot.Vulcan; +import me.frep.vulcan.spigot.config.Config; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import org.bukkit.command.CommandExecutor; +import me.frep.vulcan.spigot.command.CommandManager; + +public class PunishLogs extends CommandManager implements CommandExecutor +{ + private final ExecutorService logsExecutor; + + public PunishLogs() { + this.logsExecutor = Executors.newSingleThreadExecutor(); + } + + public boolean onCommand(final CommandSender sender, final Command command, final String alias, final String[] args) { + if (!sender.hasPermission("vulcan.punishlogs")) { + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } + if (args.length < 1) { + this.sendMessage(sender, Config.PUNISH_LOGS_SYNTAX); + return true; + } + this.logsExecutor.execute(() -> { + final String playerName = args[0]; + final String path = Vulcan.INSTANCE.getPlugin().getDataFolder() + "/punishments.txt"; + final File file = new File(path); + if (!file.exists()) { + this.sendMessage(sender, Config.NO_LOGS_FILE); + return; + } + else { + try { + final ArrayList lines = new ArrayList(); + final Scanner scanner = new Scanner(file); + while (scanner.hasNext()) { + final String line = scanner.nextLine(); + if (line.toLowerCase().contains(playerName.toLowerCase()) && line.toLowerCase().contains("was punished")) { + lines.add(line); + } + } + final ArrayList formatted = new ArrayList(); + final Iterator iterator = lines.iterator(); + while (iterator.hasNext()) { + final String string = iterator.next(); + final String replacement = string.replaceAll("-", "").replaceAll("\\[", "").replaceAll("\\]", ""); + formatted.add(replacement); + } + Collections.reverse(formatted); + int i = 1; + if (lines.isEmpty()) { + this.sendMessage(sender, Config.NO_LOGS); + } + else { + this.sendMessage(sender, Config.PUNISH_LOGS_HEADER_FOOTER.replaceAll("%player%", args[0])); + final Iterator iterator2 = formatted.iterator(); + while (iterator2.hasNext()) { + final String string2 = iterator2.next(); + this.sendMessage(sender, " &8- &7" + i + ".)" + string2); + ++i; + } + this.sendMessage(sender, Config.PUNISH_LOGS_HEADER_FOOTER.replaceAll("%player%", args[0])); + } + } + catch (final FileNotFoundException exception) { + exception.printStackTrace(); + } + return; + } + }); + return true; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/command/impl/VerboseCommand.java b/src/main/java/me/frep/vulcan/spigot/command/impl/VerboseCommand.java new file mode 100644 index 0000000..aa516b1 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/command/impl/VerboseCommand.java @@ -0,0 +1,26 @@ +package me.frep.vulcan.spigot.command.impl; + +import me.frep.vulcan.spigot.Vulcan; +import me.frep.vulcan.spigot.config.Config; +import org.bukkit.entity.Player; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.CommandExecutor; +import me.frep.vulcan.spigot.command.CommandManager; + +public class VerboseCommand extends CommandManager implements CommandExecutor +{ + public boolean onCommand(final CommandSender sender, final Command command, final String label, final String[] args) { + if (!(sender instanceof Player)) { + this.sendMessage(sender, Config.CANT_EXECUTE_FROM_CONSOLE); + return true; + } + final Player player = (Player)sender; + if (player.hasPermission("vulcan.verbose")) { + Vulcan.INSTANCE.getAlertManager().toggleVerbose(player); + return true; + } + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/command/impl/VulcanCommand.java b/src/main/java/me/frep/vulcan/spigot/command/impl/VulcanCommand.java new file mode 100644 index 0000000..0bc40b4 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/command/impl/VulcanCommand.java @@ -0,0 +1,757 @@ +package me.frep.vulcan.spigot.command.impl; + +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; +import java.util.Set; +import java.util.List; +import java.util.Iterator; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.reset.ResetManager; +import org.bukkit.util.Vector; +import java.text.DecimalFormat; +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.util.ColorUtil; +import org.bukkit.plugin.Plugin; +import me.frep.vulcan.spigot.check.AbstractCheck; +import me.frep.vulcan.api.check.Check; +import me.frep.vulcan.spigot.gui.impl.MainMenu; +import me.frep.vulcan.spigot.util.ServerUtil; +import org.bukkit.entity.Player; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import java.util.ArrayList; +import org.bukkit.Bukkit; +import java.util.stream.Collector; +import java.util.function.Supplier; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.LinkedHashMap; +import java.util.Comparator; +import java.util.Collections; +import java.util.Map; +import me.frep.vulcan.spigot.data.PlayerData; +import java.util.UUID; +import java.util.HashMap; +import me.frep.vulcan.spigot.Vulcan; +import me.frep.vulcan.spigot.config.Config; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.CommandExecutor; +import me.frep.vulcan.spigot.command.CommandManager; + +public class VulcanCommand extends CommandManager implements CommandExecutor +{ + public boolean onCommand(final CommandSender sender, final Command command, final String label, final String[] args) { + if (args.length == 0) { + if (!sender.hasPermission("vulcan.help")) { + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } + Config.HELP_COMMAND.forEach(message -> this.sendMessage(sender, message.replaceAll("%version%", Vulcan.INSTANCE.getPlugin().getDescription().getVersion()))); + } + else if (args[0].equalsIgnoreCase("help")) { + if (!sender.hasPermission("vulcan.help")) { + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } + Config.HELP_COMMAND.forEach(message -> this.sendMessage(sender, message.replaceAll("%version%", Vulcan.INSTANCE.getPlugin().getDescription().getVersion()))); + } + else if (args[0].equalsIgnoreCase("top")) { + if (!sender.hasPermission("vulcan.top")) { + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } + final Map topTotalViolations = new HashMap(); + final Map topCombatViolations = new HashMap(); + final Map topMovementViolations = new HashMap(); + final Map topPlayerViolations = new HashMap(); + for (final PlayerData data : Vulcan.INSTANCE.getPlayerDataManager().getAllData()) { + topTotalViolations.put(data.getPlayer().getUniqueId(), data.getTotalViolations()); + topCombatViolations.put(data.getPlayer().getUniqueId(), data.getCombatViolations()); + topMovementViolations.put(data.getPlayer().getUniqueId(), data.getMovementViolations()); + topPlayerViolations.put(data.getPlayer().getUniqueId(), data.getPlayerViolations()); + } + Map sortedTotal = topTotalViolations.entrySet().stream().sorted(Collections.reverseOrder(Map.Entry.comparingByValue())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (key, value) -> key, LinkedHashMap::new)); + Map sortedCombat = topCombatViolations.entrySet().stream().sorted(Collections.reverseOrder(Map.Entry.comparingByValue())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (key, value) -> key, LinkedHashMap::new)); + Map sortedMovement = topMovementViolations.entrySet().stream().sorted(Collections.reverseOrder(Map.Entry.comparingByValue())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (key, value) -> key, LinkedHashMap::new)); + Map sortedPlayer = topPlayerViolations.entrySet().stream().sorted(Collections.reverseOrder(Map.Entry.comparingByValue())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (key, value) -> key, LinkedHashMap::new)); + final Object[] totalViolationsArray = sortedTotal.keySet().toArray(); + final Object[] combatViolationsArray = sortedCombat.keySet().toArray(); + final Object[] movementViolationsArray = sortedMovement.keySet().toArray(); + final Object[] playerViolationsArray = sortedPlayer.keySet().toArray(); + UUID total1Uuid = null; + if (totalViolationsArray.length > 0 && totalViolationsArray[0] != null && totalViolationsArray[0] instanceof UUID) { + total1Uuid = (UUID)totalViolationsArray[0]; + } + UUID total2Uuid = null; + if (totalViolationsArray.length > 1 && totalViolationsArray[1] != null && totalViolationsArray[1] instanceof UUID) { + total2Uuid = (UUID)totalViolationsArray[1]; + } + UUID total3Uuid = null; + if (totalViolationsArray.length > 2 && totalViolationsArray[2] != null && totalViolationsArray[2] instanceof UUID) { + total3Uuid = (UUID)totalViolationsArray[2]; + } + UUID total4Uuid = null; + if (totalViolationsArray.length > 3 && totalViolationsArray[3] != null && totalViolationsArray[3] instanceof UUID) { + total4Uuid = (UUID)totalViolationsArray[3]; + } + UUID total5Uuid = null; + if (totalViolationsArray.length > 4 && totalViolationsArray[4] != null && totalViolationsArray[4] instanceof UUID) { + total5Uuid = (UUID)totalViolationsArray[4]; + } + Player total1Player = null; + if (total1Uuid != null) { + total1Player = Bukkit.getPlayer(total1Uuid); + } + Player total2Player = null; + if (total2Uuid != null) { + total2Player = Bukkit.getPlayer(total2Uuid); + } + Player total3Player = null; + if (total3Uuid != null) { + total3Player = Bukkit.getPlayer(total3Uuid); + } + Player total4Player = null; + if (total4Uuid != null) { + total4Player = Bukkit.getPlayer(total4Uuid); + } + Player total5Player = null; + if (total5Uuid != null) { + total5Player = Bukkit.getPlayer(total5Uuid); + } + UUID combat1Uuid = null; + if (combatViolationsArray.length > 0 && combatViolationsArray[0] != null && combatViolationsArray[0] instanceof UUID) { + combat1Uuid = (UUID)combatViolationsArray[0]; + } + UUID combat2Uuid = null; + if (combatViolationsArray.length > 1 && combatViolationsArray[1] != null && combatViolationsArray[1] instanceof UUID) { + combat2Uuid = (UUID)combatViolationsArray[1]; + } + UUID combat3Uuid = null; + if (combatViolationsArray.length > 2 && combatViolationsArray[2] != null && combatViolationsArray[2] instanceof UUID) { + combat3Uuid = (UUID)combatViolationsArray[2]; + } + UUID combat4Uuid = null; + if (combatViolationsArray.length > 3 && combatViolationsArray[3] != null && combatViolationsArray[3] instanceof UUID) { + combat4Uuid = (UUID)combatViolationsArray[3]; + } + UUID combat5Uuid = null; + if (combatViolationsArray.length > 4 && combatViolationsArray[4] != null && combatViolationsArray[4] instanceof UUID) { + combat5Uuid = (UUID)combatViolationsArray[4]; + } + Player combat1Player = null; + if (combat1Uuid != null) { + combat1Player = Bukkit.getPlayer(combat1Uuid); + } + Player combat2Player = null; + if (combat2Uuid != null) { + combat2Player = Bukkit.getPlayer(combat2Uuid); + } + Player combat3Player = null; + if (combat3Uuid != null) { + combat3Player = Bukkit.getPlayer(combat3Uuid); + } + Player combat4Player = null; + if (combat4Uuid != null) { + combat4Player = Bukkit.getPlayer(combat4Uuid); + } + Player combat5Player = null; + if (combat5Uuid != null) { + combat5Player = Bukkit.getPlayer(combat5Uuid); + } + UUID movement1Uuid = null; + if (movementViolationsArray.length > 0 && movementViolationsArray[0] != null && movementViolationsArray[0] instanceof UUID) { + movement1Uuid = (UUID)movementViolationsArray[0]; + } + UUID movement2Uuid = null; + if (movementViolationsArray.length > 1 && movementViolationsArray[1] != null && movementViolationsArray[1] instanceof UUID) { + movement2Uuid = (UUID)movementViolationsArray[1]; + } + UUID movement3Uuid = null; + if (movementViolationsArray.length > 2 && movementViolationsArray[2] != null && movementViolationsArray[2] instanceof UUID) { + movement3Uuid = (UUID)movementViolationsArray[2]; + } + UUID movement4Uuid = null; + if (movementViolationsArray.length > 3 && movementViolationsArray[3] != null && movementViolationsArray[3] instanceof UUID) { + movement4Uuid = (UUID)movementViolationsArray[3]; + } + UUID movement5Uuid = null; + if (movementViolationsArray.length > 4 && movementViolationsArray[4] != null && movementViolationsArray[4] instanceof UUID) { + movement5Uuid = (UUID)movementViolationsArray[4]; + } + Player movement1Player = null; + if (movement1Uuid != null) { + movement1Player = Bukkit.getPlayer(movement1Uuid); + } + Player movement2Player = null; + if (movement2Uuid != null) { + movement2Player = Bukkit.getPlayer(movement2Uuid); + } + Player movement3Player = null; + if (movement3Uuid != null) { + movement3Player = Bukkit.getPlayer(movement3Uuid); + } + Player movement4Player = null; + if (movement4Uuid != null) { + movement4Player = Bukkit.getPlayer(movement4Uuid); + } + Player movement5Player = null; + if (movement5Uuid != null) { + movement5Player = Bukkit.getPlayer(movement5Uuid); + } + UUID player1Uuid = null; + if (playerViolationsArray.length > 0 && playerViolationsArray[0] != null && playerViolationsArray[0] instanceof UUID) { + player1Uuid = (UUID)playerViolationsArray[0]; + } + UUID player2Uuid = null; + if (playerViolationsArray.length > 1 && playerViolationsArray[1] != null && playerViolationsArray[1] instanceof UUID) { + player2Uuid = (UUID)playerViolationsArray[1]; + } + UUID player3Uuid = null; + if (playerViolationsArray.length > 2 && playerViolationsArray[2] != null && playerViolationsArray[2] instanceof UUID) { + player3Uuid = (UUID)playerViolationsArray[2]; + } + UUID player4Uuid = null; + if (playerViolationsArray.length > 3 && playerViolationsArray[3] != null && playerViolationsArray[3] instanceof UUID) { + player4Uuid = (UUID)playerViolationsArray[3]; + } + UUID player5Uuid = null; + if (playerViolationsArray.length > 4 && playerViolationsArray[4] != null && playerViolationsArray[4] instanceof UUID) { + player5Uuid = (UUID)playerViolationsArray[4]; + } + Player player1Player = null; + if (player1Uuid != null) { + player1Player = Bukkit.getPlayer(player1Uuid); + } + Player player2Player = null; + if (player2Uuid != null) { + player2Player = Bukkit.getPlayer(player2Uuid); + } + Player player3Player = null; + if (player3Uuid != null) { + player3Player = Bukkit.getPlayer(player3Uuid); + } + Player player4Player = null; + if (player4Uuid != null) { + player4Player = Bukkit.getPlayer(player4Uuid); + } + Player player5Player = null; + if (player5Uuid != null) { + player5Player = Bukkit.getPlayer(player5Uuid); + } + final String total1PlayerName = (total1Player == null) ? Config.TOP_COMMAND_UNRESOLVED : total1Player.getName(); + final String total2PlayerName = (total2Player == null) ? Config.TOP_COMMAND_UNRESOLVED : total2Player.getName(); + final String total3PlayerName = (total3Player == null) ? Config.TOP_COMMAND_UNRESOLVED : total3Player.getName(); + final String total4PlayerName = (total4Player == null) ? Config.TOP_COMMAND_UNRESOLVED : total4Player.getName(); + final String total5PlayerName = (total5Player == null) ? Config.TOP_COMMAND_UNRESOLVED : total5Player.getName(); + final String total1Vl = (total1Uuid == null) ? "0" : sortedTotal.get(total1Uuid).toString(); + final String total2Vl = (total2Uuid == null) ? "0" : sortedTotal.get(total2Uuid).toString(); + final String total3Vl = (total3Uuid == null) ? "0" : sortedTotal.get(total3Uuid).toString(); + final String total4Vl = (total4Uuid == null) ? "0" : sortedTotal.get(total4Uuid).toString(); + final String total5Vl = (total5Uuid == null) ? "0" : sortedTotal.get(total5Uuid).toString(); + final String combat1PlayerName = (combat1Player == null) ? Config.TOP_COMMAND_UNRESOLVED : combat1Player.getName(); + final String combat2PlayerName = (combat2Player == null) ? Config.TOP_COMMAND_UNRESOLVED : combat2Player.getName(); + final String combat3PlayerName = (combat3Player == null) ? Config.TOP_COMMAND_UNRESOLVED : combat3Player.getName(); + final String combat4PlayerName = (combat4Player == null) ? Config.TOP_COMMAND_UNRESOLVED : combat4Player.getName(); + final String combat5PlayerName = (combat5Player == null) ? Config.TOP_COMMAND_UNRESOLVED : combat5Player.getName(); + final String combat1Vl = (combat1Uuid == null) ? "0" : sortedCombat.get(combat1Uuid).toString(); + final String combat2Vl = (combat2Uuid == null) ? "0" : sortedCombat.get(combat2Uuid).toString(); + final String combat3Vl = (combat3Uuid == null) ? "0" : sortedCombat.get(combat3Uuid).toString(); + final String combat4Vl = (combat4Uuid == null) ? "0" : sortedCombat.get(combat4Uuid).toString(); + final String combat5Vl = (combat5Uuid == null) ? "0" : sortedCombat.get(combat5Uuid).toString(); + final String movement1PlayerName = (movement1Player == null) ? Config.TOP_COMMAND_UNRESOLVED : movement1Player.getName(); + final String movement2PlayerName = (movement2Player == null) ? Config.TOP_COMMAND_UNRESOLVED : movement2Player.getName(); + final String movement3PlayerName = (movement3Player == null) ? Config.TOP_COMMAND_UNRESOLVED : movement3Player.getName(); + final String movement4PlayerName = (movement4Player == null) ? Config.TOP_COMMAND_UNRESOLVED : movement4Player.getName(); + final String movement5PlayerName = (movement5Player == null) ? Config.TOP_COMMAND_UNRESOLVED : movement5Player.getName(); + final String movement1Vl = (movement1Uuid == null) ? "0" : sortedMovement.get(movement1Uuid).toString(); + final String movement2Vl = (movement2Uuid == null) ? "0" : sortedMovement.get(movement2Uuid).toString(); + final String movement3Vl = (movement3Uuid == null) ? "0" : sortedMovement.get(movement3Uuid).toString(); + final String movement4Vl = (movement4Uuid == null) ? "0" : sortedMovement.get(movement4Uuid).toString(); + final String movement5Vl = (movement5Uuid == null) ? "0" : sortedMovement.get(movement5Uuid).toString(); + final String player1PlayerName = (player1Player == null) ? Config.TOP_COMMAND_UNRESOLVED : player1Player.getName(); + final String player2PlayerName = (player2Player == null) ? Config.TOP_COMMAND_UNRESOLVED : player2Player.getName(); + final String player3PlayerName = (player3Player == null) ? Config.TOP_COMMAND_UNRESOLVED : player3Player.getName(); + final String player4PlayerName = (player4Player == null) ? Config.TOP_COMMAND_UNRESOLVED : player4Player.getName(); + final String player5PlayerName = (player5Player == null) ? Config.TOP_COMMAND_UNRESOLVED : player5Player.getName(); + final String player1Vl = (player1Uuid == null) ? "0" : sortedPlayer.get(player1Uuid).toString(); + final String player2Vl = (player2Uuid == null) ? "0" : sortedPlayer.get(player2Uuid).toString(); + final String player3Vl = (player3Uuid == null) ? "0" : sortedPlayer.get(player3Uuid).toString(); + final String player4Vl = (player4Uuid == null) ? "0" : sortedPlayer.get(player4Uuid).toString(); + final String player5Vl = (player5Uuid == null) ? "0" : sortedPlayer.get(player5Uuid).toString(); + Config.TOP_COMMAND.forEach(message -> this.sendMessage(sender, message.replaceAll("%total-1-name%", total1PlayerName).replaceAll("%total-2-name%", total2PlayerName).replaceAll("%total-3-name%", total3PlayerName).replaceAll("%total-4-name%", total4PlayerName).replaceAll("%total-5-name%", total5PlayerName).replaceAll("%total-1-violations%", total1Vl).replaceAll("%total-2-violations%", total2Vl).replaceAll("%total-3-violations%", total3Vl).replaceAll("%total-4-violations%", total4Vl).replaceAll("%total-5-violations%", total5Vl).replaceAll("%combat-1-name%", combat1PlayerName).replaceAll("%combat-2-name%", combat2PlayerName).replaceAll("%combat-3-name%", combat3PlayerName).replaceAll("%combat-4-name%", combat4PlayerName).replaceAll("%combat-5-name%", combat5PlayerName).replaceAll("%combat-1-violations%", combat1Vl).replaceAll("%combat-2-violations%", combat2Vl).replaceAll("%combat-3-violations%", combat3Vl).replaceAll("%combat-4-violations%", combat4Vl).replaceAll("%combat-5-violations%", combat5Vl).replaceAll("%movement-1-name%", movement1PlayerName).replaceAll("%movement-2-name%", movement2PlayerName).replaceAll("%movement-3-name%", movement3PlayerName).replaceAll("%movement-4-name%", movement4PlayerName).replaceAll("%movement-5-name%", movement5PlayerName).replaceAll("%movement-1-violations%", movement1Vl).replaceAll("%movement-2-violations%", movement2Vl).replaceAll("%movement-3-violations%", movement3Vl).replaceAll("%movement-4-violations%", movement4Vl).replaceAll("%movement-5-violations%", movement5Vl).replaceAll("%player-1-name%", player1PlayerName).replaceAll("%player-2-name%", player2PlayerName).replaceAll("%player-3-name%", player3PlayerName).replaceAll("%player-4-name%", player4PlayerName).replaceAll("%player-5-name%", player5PlayerName).replaceAll("%player-1-violations%", player1Vl).replaceAll("%player-2-violations%", player2Vl).replaceAll("%player-3-violations%", player3Vl).replaceAll("%player-4-violations%", player4Vl).replaceAll("%player-5-violations%", player5Vl))); + } + else if (args[0].equalsIgnoreCase("exempts")) { + if (!sender.hasPermission("vulcan.exempts")) { + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } + if (args.length == 1) { + this.sendMessage(sender, "must include player parameter"); + } + else { + final String name = args[1]; + final Player player = Bukkit.getPlayer(name); + if (player == null) { + this.sendMessage(sender, Config.INVALID_TARGET); + return true; + } + final PlayerData data2 = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data2 == null) { + this.sendMessage(sender, Config.INVALID_TARGET); + return true; + } + final List exempts = new ArrayList(); + for (final ExemptType exemptType : ExemptType.values()) { + if (data2.getExemptProcessor().isExempt(exemptType)) { + exempts.add(exemptType.toString()); + } + } + this.sendLine(sender); + this.sendMessage(sender, "&cExemptions:"); + exempts.forEach(exemption -> this.sendMessage(sender, " &8- &7" + exemption)); + this.sendMessage(sender, "&cBypass Permission: " + player.hasPermission("vulcan.bypass.speeda")); + this.sendLine(sender); + } + } + else if (args[0].equalsIgnoreCase("menu") || args[0].equalsIgnoreCase("gui")) { + if (!(sender instanceof Player)) { + this.sendMessage(sender, Config.CANT_EXECUTE_FROM_CONSOLE); + return true; + } + if (!sender.hasPermission("vulcan.gui") && !sender.hasPermission("vulcan.menu")) { + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } + if (ServerUtil.isLowerThan1_8()) { + this.sendMessage(sender, "&cGUI unavailable on 1.7 servers!"); + } + else { + MainMenu.getInstance().open((Player)sender); + } + } + else if (args[0].equalsIgnoreCase("reload")) { + if (!sender.hasPermission("vulcan.reload")) { + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } + Vulcan.INSTANCE.reload(); + this.sendMessage(sender, Config.RELOAD_SUCCESS); + } + else if (args[0].equalsIgnoreCase("testalert")) { + if (!sender.hasPermission("vulcan.testalert")) { + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } + if (!(sender instanceof Player)) { + this.sendMessage(sender, Config.CANT_EXECUTE_FROM_CONSOLE); + return true; + } + final Player player2 = (Player)sender; + final PlayerData data3 = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player2); + if (data3 == null) { + this.sendMessage(sender, Config.INVALID_TARGET); + return true; + } + if (sender.hasPermission("vulcan.bypass.speeda")) { + this.sendLine(sender); + this.sendMessage(sender, "&4&lNOTE! &cThis command emulates a real alert message, so if you are OP or have the bypass permission it will not work! If you use LuckPerms, you can negate the bypass permission by doing:"); + this.sendMessage(sender, " &8- &c/lp user " + sender.getName() + " permission set vulcan.bypass.* false"); + this.sendLine(sender); + return true; + } + for (final Check check : data3.getChecks()) { + if (check.getDisplayName().toLowerCase().equals("speed") && Character.toString(check.getDisplayType()).toLowerCase().equals("a")) { + Bukkit.getScheduler().runTaskAsynchronously(Vulcan.INSTANCE.getPlugin(), () -> { + Vulcan.INSTANCE.getAlertManager().handleAlert((AbstractCheck)check, data3, "Test Alert!"); + Vulcan.INSTANCE.getAlertManager().handleAlert((AbstractCheck)check, data3, "Test Alert!"); + Vulcan.INSTANCE.getAlertManager().handleAlert((AbstractCheck)check, data3, "Test Alert!"); + return; + }); + } + } + this.sendMessage(sender, Config.SENT_TEST_ALERT); + return true; + } + else if (args[0].equalsIgnoreCase("clickalert")) { + if (!sender.hasPermission("vulcan.clickalert")) { + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } + if (!(sender instanceof Player)) { + this.sendMessage(sender, Config.CANT_EXECUTE_FROM_CONSOLE); + return true; + } + if (args.length == 1) { + this.sendMessage(sender, "&cInvalid syntax!"); + } + else { + final String name = args[1]; + final Player player = Bukkit.getPlayer(name); + if (player == null) { + this.sendMessage(sender, Config.INVALID_TARGET); + } + else { + final Player staff = (Player)sender; + Config.CLICKALERT_COMMAND_COMMANDS.forEach(message -> staff.performCommand(message.replaceAll("%player%", player.getName()))); + } + } + } + else if (args[0].equalsIgnoreCase("disablecheck")) { + if (!sender.hasPermission("vulcan.disablecheck")) { + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } + if (args.length == 1) { + this.sendMessage(sender, Config.DISABLE_CHECK_COMMAND_SYNTAX); + } + else { + final String checkName = args[1]; + if (!Config.ENABLED_CHECKS.containsKey(checkName) || !Config.ENABLED_CHECKS.get(checkName)) { + this.sendMessage(sender, Config.INVALID_CHECK); + return true; + } + Config.ENABLED_CHECKS.remove(checkName); + Config.ENABLED_CHECKS.put(checkName, false); + this.sendMessage(sender, Config.DISABLED_CHECK.replaceAll("%check%", checkName)); + } + } + else if (args[0].equalsIgnoreCase("freeze")) { + if (!sender.hasPermission("vulcan.freeze")) { + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } + if (args.length == 1) { + this.sendMessage(sender, Config.FREEZE_COMMAND_SYNTAX); + return true; + } + final String name = args[1]; + final Player player = Bukkit.getPlayer(name); + if (player == null) { + this.sendMessage(sender, Config.INVALID_TARGET); + return true; + } + final PlayerData data2 = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data2 == null) { + this.sendMessage(sender, Config.INVALID_TARGET); + return true; + } + final boolean frozen = data2.getPositionProcessor().isFrozen(); + if (frozen) { + data2.getPositionProcessor().setFrozen(false); + this.sendMessage(sender, Config.UNFROZE.replaceAll("%player%", player.getName())); + Vulcan.INSTANCE.getAlertManager().sendMessage(ColorUtil.translate(Config.STAFF_UNFROZE_BROADCAST.replaceAll("%player%", player.getName()).replaceAll("%staff%", sender.getName()))); + } + else { + data2.getPositionProcessor().setFrozen(true); + this.sendMessage(sender, Config.FROZE.replaceAll("%player%", player.getName())); + Vulcan.INSTANCE.getAlertManager().sendMessage(ColorUtil.translate(Config.STAFF_FROZE_BROADCAST.replaceAll("%player%", player.getName()).replaceAll("%staff%", sender.getName()))); + } + } + else if (args[0].equalsIgnoreCase("ban")) { + if (!sender.hasPermission("vulcan.ban")) { + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } + if (args.length == 1) { + this.sendMessage(sender, Config.BAN_COMMAND_SYNTAX); + } + else { + final String name = args[1]; + final Player player = Bukkit.getPlayer(name); + if (player == null) { + this.sendMessage(sender, Config.INVALID_TARGET); + return true; + } + for (final String string : Config.BAN_COMMANDS) { + if (string.startsWith("Bungee:") || string.startsWith("bungee")) { + this.sendPluginMessage(player, ColorUtil.translate(string.replaceAll("Bungee:", "").replaceAll("bungee:", "")).replaceAll("%player%", name)); + } + else { + ServerUtil.dispatchCommand(ColorUtil.translate(string.replaceAll("%player%", name))); + } + } + Config.BAN_COMMAND_BROADCAST.forEach(message -> ServerUtil.broadcast(message.replaceAll("%player%", name))); + } + } + else if (args[0].equalsIgnoreCase("shuffle")) { + if (sender.hasPermission("vulcan.shuffle")) { + if (args.length == 1) { + this.sendMessage(sender, Config.SHUFFLE_COMMAND_SYNTAX); + } + else { + final String name = args[1]; + final Player player = Bukkit.getPlayer(name); + if (player == null) { + this.sendMessage(sender, Config.INVALID_TARGET); + return true; + } + PlayerUtil.shuffleHotbar(player); + this.sendMessage(sender, Config.SHUFFLED_HOTBAR.replaceAll("%player%", name)); + } + } + } + else if (args[0].equalsIgnoreCase("rotate")) { + if (sender.hasPermission("vulcan.rotate")) { + if (args.length == 1) { + this.sendMessage(sender, Config.ROTATE_COMMAND_SYNTAX); + } + else { + final String name = args[1]; + final Player player = Bukkit.getPlayer(name); + if (player == null) { + this.sendMessage(sender, Config.INVALID_TARGET); + return true; + } + PlayerUtil.rotateRandomly(player); + this.sendMessage(sender, Config.RANDOMLY_ROTATED.replaceAll("%player%", name)); + } + } + } + else if (args[0].equalsIgnoreCase("violations")) { + if (!sender.hasPermission("vulcan.violations")) { + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } + if (args.length == 1) { + this.sendMessage(sender, Config.VIOLATIONS_COMMAND_SYNTAX); + } + else { + final String name = args[1]; + final Player player = Bukkit.getPlayer(name); + if (player == null) { + this.sendMessage(sender, Config.INVALID_TARGET); + return true; + } + final PlayerData data2 = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data2 == null) { + this.sendMessage(sender, Config.INVALID_TARGET); + return true; + } + final int totalViolations = data2.getTotalViolations(); + if (totalViolations < 1) { + this.sendMessage(sender, Config.NO_LOGS); + return true; + } + this.sendLine(sender); + this.sendMessage(sender, "&7Total Violations for &c" + name + " &7(&c" + totalViolations + "&7):"); + for (final AbstractCheck check2 : data2.getChecks()) { + if (check2.getVl() > 0) { + this.sendMessage(sender, " &8- &b" + check2.getCheckInfo().name() + " &7(&bType " + Character.toUpperCase(check2.getType()) + "&7) VL: " + check2.getVl()); + } + } + this.sendLine(sender); + } + } + else if (args[0].equalsIgnoreCase("cps")) { + if (!sender.hasPermission("vulcan.cps")) { + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } + if (args.length == 1) { + this.sendMessage(sender, Config.CPS_COMMAND_SYNTAX); + } + else { + final String name = args[1]; + final Player player = Bukkit.getPlayer(name); + if (player == null) { + this.sendMessage(sender, Config.INVALID_TARGET); + return true; + } + final PlayerData data2 = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data2 == null) { + this.sendMessage(sender, Config.INVALID_TARGET); + return true; + } + final String cps = new DecimalFormat("##.##").format(data2.getClickProcessor().getCps()); + this.sendMessage(sender, Config.CPS_COMMAND.replaceAll("%cps%", cps).replace("%player%", name)); + } + } + else if (args[0].equalsIgnoreCase("kb") || args[0].equalsIgnoreCase("knockback")) { + if (!sender.hasPermission("vulcan.kb") && !sender.hasPermission("vulcan.knockback")) { + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } + if (args.length == 1) { + this.sendMessage(sender, Config.KB_COMMAND_SYNTAX); + } + else { + final String name = args[1]; + final Player player = Bukkit.getPlayer(name); + if (player == null) { + this.sendMessage(sender, Config.INVALID_TARGET); + return true; + } + final Vector vector = new Vector(0.75, 0.5, 0.75); + player.setVelocity(vector); + this.sendMessage(sender, Config.KB_TEST_SUCCESS.replaceAll("%player%", name)); + } + } + else if (args[0].equalsIgnoreCase("checks")) { + if (!sender.hasPermission("vulcan.checks")) { + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } + this.sendLine(sender); + this.sendMessage(sender, "&7Total Enabled Checks: &c" + Config.ENABLED_CHECKS.size()); + final Set checks = Config.ENABLED_CHECKS.keySet(); + final List checkList = new ArrayList(); + checks.forEach(check -> checkList.add(check)); + Collections.sort(checkList); + for (final String string : checkList) { + if (Config.ENABLED_CHECKS.get(string)) { + this.sendMessage(sender, " &8- &7" + string); + } + } + this.sendLine(sender); + } + else if (args[0].equalsIgnoreCase("reset")) { + if (!sender.hasPermission("vulcan.reset")) { + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } + if (args.length == 1) { + ResetManager.reset(); + } + else { + final String name = args[1]; + final Player player = Bukkit.getPlayer(name); + if (player == null) { + this.sendMessage(sender, Config.INVALID_TARGET); + return true; + } + final PlayerData data2 = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data2 == null) { + this.sendMessage(sender, Config.INVALID_TARGET); + return true; + } + for (final Check check3 : data2.getChecks()) { + check3.setVl(0); + check3.setBuffer(0.0); + } + data2.setMovementViolations(0); + data2.setTotalViolations(0); data2.setCombatViolations(0); + data2.setAutoClickerViolations(0); + data2.setScaffoldViolations(0); + data2.setPlayerViolations(0); + data2.setTimerViolations(0); + this.sendMessage(sender, Config.VIOLATIONS_RESET.replaceAll("%player%", name)); + } + } + else if (args[0].equalsIgnoreCase("license")) { + if (sender.getName().equalsIgnoreCase("frep") || sender.getName().equals("bloaaie")) { + this.sendLine(sender); + this.sendMessage(sender, "&7This copy is licensed to:"); + this.sendMessage(sender, " &8- &7ID: &c" + Vulcan.INSTANCE.getSpigot()); + this.sendMessage(sender, " &8- &7Nonce: &c" + Vulcan.INSTANCE.getNonce()); + this.sendMessage(sender, " &8- &7Spigot Profile: &chttps://www.spigotmc.org/members/" + Vulcan.INSTANCE.getSpigot() + "/"); + this.sendLine(sender); + } + else { + this.sendMessage(sender, "&cUnknown command!"); + } + } + else if (args[0].equalsIgnoreCase("connection")) { + if (!sender.hasPermission("vulcan.connection")) { + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } + if (args.length == 1) { + this.sendMessage(sender, Config.CONNECTION_COMMAND_SYNTAX); + } + else { + final String name = args[1]; + final Player player = Bukkit.getPlayer(name); + if (player == null) { + this.sendMessage(sender, Config.INVALID_TARGET); + return true; + } + final PlayerData data2 = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data2 == null) { + this.sendMessage(sender, Config.INVALID_TARGET); + return true; + } + final long now = System.currentTimeMillis(); + final String transactionPing = Long.toString(data2.getConnectionProcessor().getTransactionPing()); + final String keepAlivePing = Integer.toString(data2.getConnectionProcessor().getKeepAlivePing()); + final String lastRepliedTransaction = Long.toString(now - data2.getConnectionProcessor().getLastRepliedTransaction()); + final String flyingDelay = Long.toString(data2.getConnectionProcessor().getFlyingDelay()); + final String queuedTransactions = Integer.toString(data2.getPendingTransactions()); + Config.CONNECTION_COMMAND.forEach(message -> this.sendMessage(sender, message.replaceAll("%player%", player.getName()).replaceAll("%transaction-ping%", transactionPing).replaceAll("%keepalive-ping%", keepAlivePing).replaceAll("%queued-transactions%", queuedTransactions).replaceAll("%last-replied-transaction%", lastRepliedTransaction).replaceAll("%flying-delay%", flyingDelay))); + } + } + else if (args[0].equalsIgnoreCase("dump")) { + if (!sender.hasPermission("vulcan.dump")) { + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } + this.sendLine(sender); + this.sendMessage(sender, "&7Vulcan Version: &c" + Vulcan.INSTANCE.getPlugin().getDescription().getVersion()); + this.sendMessage(sender, "&7Server Version: &c" + ServerUtil.getServerVersion()); + this.sendMessage(sender, "&7Server Software: &c" + Bukkit.getVersion()); + this.sendMessage(sender, "&7TPS: &c" + ServerUtil.getTPS()); + this.sendMessage(sender, "&7ID: &c" + Vulcan.INSTANCE.getSpigot()); + this.sendMessage(sender, "&7Nonce: &c" + Vulcan.INSTANCE.getNonce()); + this.sendLine(sender); + } + else { + if (!args[0].equalsIgnoreCase("profile")) { + this.sendMessage(sender, Config.UNKNOWN_COMMAND); + return true; + } + if (!sender.hasPermission("vulcan.profile")) { + this.sendMessage(sender, Config.NO_PERMISSION); + return true; + } + if (args.length == 1) { + this.sendMessage(sender, Config.PROFILE_COMMAND_SYNTAX); + } + else { + final String name = args[1]; + final Player player = Bukkit.getPlayer(name); + if (player == null) { + this.sendMessage(sender, Config.INVALID_TARGET); + return true; + } + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data != null) { + if (ServerUtil.isHigherThan1_13()) { + final String clientBrand = (data.getClientBrand() == null) ? "Unresolved" : data.getClientBrand(); + final String sensitivity = Integer.toString(data.getRotationProcessor().getSensitivity()); + final String totalViolations = Integer.toString(data.getTotalViolations()); + final String combatViolations = Integer.toString(data.getCombatViolations()); + final String movementViolations = Integer.toString(data.getMovementViolations()); + final String playerViolations = Integer.toString(data.getPlayerViolations()); + final String clientVersion = PlayerUtil.getClientVersionToString(data.getPlayer()); + final String cps = MathUtil.trim(data.getClickProcessor().getCps()); + final String uuid = data.getPlayer().getUniqueId().toString(); + final String nearbyBlocks = (data.getPositionProcessor().getNearbyBlocksModern() == null) ? "Empty" : data.getPositionProcessor().getNearbyBlocksModern().toString(); + final String nearbyEntities = (data.getPositionProcessor().getNearbyEntities() == null) ? "Empty" : data.getPositionProcessor().getNearbyEntities().toString(); + Config.PROFILE_COMMAND.forEach(message -> this.sendMessage(sender, message.replaceAll("%player%", name).replaceAll("%client-brand%", clientBrand).replaceAll("%cps%", cps).replaceAll("%uuid%", uuid).replaceAll("%x%", Integer.toString(data.getPositionProcessor().getBlockX())).replaceAll("%y%", Integer.toString(data.getPositionProcessor().getBlockY())).replaceAll("%z%", Integer.toString(data.getPositionProcessor().getBlockZ())).replaceAll("%world%", data.getPlayer().getWorld().getName()).replaceAll("%potion-effects%", data.getPlayer().getActivePotionEffects().toString()).replaceAll("%nearby-blocks%", nearbyBlocks).replaceAll("%nearby-entities%", nearbyEntities).replaceAll("%client-version%", clientVersion).replaceAll("%total-violations%", totalViolations).replaceAll("%combat-violations%", combatViolations).replaceAll("%movement-violations%", movementViolations).replaceAll("%player-violations%", playerViolations).replaceAll("%sensitivity%", sensitivity))); + } + else { + final String clientBrand = (data.getClientBrand() == null) ? "Unresolved" : data.getClientBrand(); + final String sensitivity = Integer.toString(data.getRotationProcessor().getSensitivity()); + final String totalViolations = Integer.toString(data.getTotalViolations()); + final String combatViolations = Integer.toString(data.getCombatViolations()); + final String movementViolations = Integer.toString(data.getMovementViolations()); + final String playerViolations = Integer.toString(data.getPlayerViolations()); + final String clientVersion = PlayerUtil.getClientVersionToString(data.getPlayer()); + final String cps = MathUtil.trim(data.getClickProcessor().getCps()); + final String uuid = data.getPlayer().getUniqueId().toString(); + final String nearbyBlocks = (data.getPositionProcessor().getNearbyBlocks() == null) ? "Empty" : data.getPositionProcessor().getNearbyBlocks().toString(); + final String nearbyEntities = (data.getPositionProcessor().getNearbyEntities() == null) ? "Empty" : data.getPositionProcessor().getNearbyEntities().toString(); + Config.PROFILE_COMMAND.forEach(message -> this.sendMessage(sender, message.replaceAll("%player%", name).replaceAll("%client-brand%", clientBrand).replaceAll("%cps%", cps).replaceAll("%uuid%", uuid).replaceAll("%x%", Integer.toString(data.getPositionProcessor().getBlockX())).replaceAll("%y%", Integer.toString(data.getPositionProcessor().getBlockY())).replaceAll("%z%", Integer.toString(data.getPositionProcessor().getBlockZ())).replaceAll("%world%", data.getPlayer().getWorld().getName()).replaceAll("%potion-effects%", data.getPlayer().getActivePotionEffects().toString()).replaceAll("%nearby-blocks%", nearbyBlocks).replaceAll("%nearby-entities%", nearbyEntities).replaceAll("%client-version%", clientVersion).replaceAll("%total-violations%", totalViolations).replaceAll("%combat-violations%", combatViolations).replaceAll("%movement-violations%", movementViolations).replaceAll("%player-violations%", playerViolations).replaceAll("%sensitivity%", sensitivity))); + } + } + } + } + return true; + } + + private void sendPluginMessage(final Player player, final String msg) { + final ByteArrayDataOutput out = ByteStreams.newDataOutput(); + out.writeUTF("punishment"); + out.writeUTF(msg); + player.sendPluginMessage(Vulcan.INSTANCE.getPlugin(), "vulcan:bungee", out.toByteArray()); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/command/tab/VulcanTabCompleter.java b/src/main/java/me/frep/vulcan/spigot/command/tab/VulcanTabCompleter.java new file mode 100644 index 0000000..6433247 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/command/tab/VulcanTabCompleter.java @@ -0,0 +1,45 @@ +package me.frep.vulcan.spigot.command.tab; + +import javax.annotation.Nullable; +import me.frep.vulcan.spigot.config.Config; +import java.util.Collection; +import org.bukkit.util.StringUtil; +import java.util.ArrayList; +import java.util.List; +import org.bukkit.command.Command; +import org.jetbrains.annotations.NotNull; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; + +public class VulcanTabCompleter implements TabCompleter +{ + @Nullable + public List onTabComplete(@NotNull final CommandSender sender, @NotNull final Command command, @NotNull final String alias, final String[] args) { + if (args.length == 1) { + final List arguments = new ArrayList(); + arguments.add("help"); + arguments.add("menu"); + arguments.add("gui"); + arguments.add("profile"); + arguments.add("ban"); + arguments.add("reload"); + arguments.add("disablecheck"); + arguments.add("violations"); + arguments.add("cps"); + arguments.add("checks"); + arguments.add("kb"); + arguments.add("reset"); + arguments.add("knockback"); + arguments.add("connection"); + arguments.add("freeze"); + arguments.add("rotate"); + arguments.add("shuffle"); + arguments.add("top"); + return (List)StringUtil.copyPartialMatches(args[0], arguments, new ArrayList()); + } + if (args.length == 2 && args[0].equalsIgnoreCase("disablecheck")) { + return (List)StringUtil.copyPartialMatches(args[0], Config.ENABLED_CHECKS.keySet(), new ArrayList()); + } + return null; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/config/Config.java b/src/main/java/me/frep/vulcan/spigot/config/Config.java new file mode 100644 index 0000000..fdac12c --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/config/Config.java @@ -0,0 +1,834 @@ +package me.frep.vulcan.spigot.config; + +import java.util.HashMap; +import org.bukkit.Color; +import org.bukkit.Bukkit; +import me.frep.vulcan.spigot.util.CacheUtil; +import java.io.OutputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.util.logging.Level; +import java.util.Date; +import me.frep.vulcan.spigot.Vulcan; +import java.io.File; +import me.frep.vulcan.spigot.config.type.CommentedConfiguration; +import java.util.List; +import me.frep.vulcan.api.check.ICheckData; +import java.util.Map; + +public final class Config +{ + public static final Map CHECK_DATA; + public static final Map ENABLED_CHECKS; + public static final Map MAX_VIOLATIONS; + public static final Map ALERT_INTERVAL; + public static final Map MINIMUM_VL_TO_NOTIFY; + public static final Map> PUNISHMENT_COMMANDS; + public static final Map PUNISHABLE; + public static final Map BROADCAST_PUNISHMENT; + public static final Map MAXIMUM_PING; + public static final Map MINIMUM_TPS; + public static final Map SETBACKS; + public static final Map MAX_BUFFERS; + public static final Map BUFFER_DECAYS; + public static final Map BUFFER_MULTIPLES; + public static final Map HOTBAR_SHUFFLE; + public static final Map HOTBAR_SHUFFLE_MINIMUM; + public static final Map HOTBAR_SHUFFLE_EVERY; + public static final Map RANDOM_ROTATION; + public static final Map RANDOM_ROTATION_MINIMUM; + public static final Map RANDOM_ROTATION_EVERY; + public static final Map DISCORD_ALERT_INTERVAL; + public static final Map MINIMUM_VIOLATIONS_TO_SETBACK; + public static String PREFIX; + public static String NO_PERMISSION; + public static String ALERTS_FORMAT; + public static String ALERTS_ENABLED; + public static String ALERTS_DISABLED; + public static String CANT_EXECUTE_FROM_CONSOLE; + public static String PUNISHMENT_MESSAGE; + public static String BAN_COMMAND_SYNTAX; + public static String RELOAD_SUCCESS; + public static String KB_COMMAND_SYNTAX; + public static String INVALID_TARGET; + public static String KB_TEST_SUCCESS; + public static String JDAY_COMMAND_SYNTAX; + public static String JDAY_NO_PENDING_BANS; + public static String JDAY_ADDED_TO_LIST; + public static String RESET_COMMAND; + public static String PROFILE_COMMAND_SYNTAX; + public static String CLIENT_BRAND_ALERT_MESSAGE; + public static String VERBOSE_ENABLED; + public static String VERBOSE_DISABLED; + public static String VERBOSE_FORMAT; + public static String VIOLATION_RESET_MESSAGE; + public static String ALERTS_CONSOLE_FORMAT; + public static String LOG_FILE_ALERT_MESSAGE; + public static String LOG_FILE_PUNISHMENT_MESSAGE; + public static String ALERTS_SEVERITY_COLOR_1; + public static String ALERTS_SEVERITY_COLOR_2; + public static String ALERTS_SEVERITY_COLOR_3; + public static String ALERTS_SEVERITY_COLOR_4; + public static String ALERTS_SEVERITY_COLOR_5; + public static String CPS_COMMAND; + public static String NO_NEXT_PAGE; + public static String NO_PREVIOUS_PAGE; + public static String ENABLED_ALL_CHECKS; + public static String DISABLED_ALL_CHECKS; + public static String ENABLED_ALL_PUNISHMENTS; + public static String DISABLED_ALL_PUNISHMENTS; + public static String ENABLED_CHECK; + public static String DISABLED_CHECK; + public static String ENABLED_PUNISHMENT; + public static String DISABLED_PUNISHMENT; + public static String ENABLED_HOTBAR_SHUFFLE; + public static String DISABLED_HOTBAR_SHUFFLE; + public static String ENABLED_RANDOM_ROTATION; + public static String DISABLED_RANDOM_ROTATION; + public static String ENABLED_BROADCAST_PUNISHMENT; + public static String DISABLED_BROADCAST_PUNISHMENT; + public static String MUST_BE_AN_INTEGER; + public static String MUST_BE_POSITIVE; + public static String SET_MAX_BUFFER; + public static String SET_HOTBAR_SHUFFLE_MINIMUM_VIOLATIONS; + public static String SET_HOTBAR_SHUFFLE_INTERVAL; + public static String SET_RANDOM_ROTATION_MINIMUM_VIOLATIONS; + public static String SET_RANDOM_ROTATION_INTERVAL; + public static String SET_ALERT_INTERVAL; + public static String MUST_BE_NUMBER; + public static String SET_BUFFER_MULTIPLE; + public static String SET_BUFFER_DECAY; + public static String SET_MAX_VIOLATIONS; + public static String SET_MINIMUM_VIOLATIONS_TO_ALERT; + public static String SET_MAXIMUM_PING; + public static String SET_MINIMUM_TPS; + public static String REMOVED_PUNISHMENT_COMMAND; + public static String INVALID_INDEX_NUMBER; + public static String STOPPED_EDITING_PUNISHMENT_COMMANDS; + public static String ADDED_PUNISHMENT_COMMAND; + public static String ENTER_PUNISHMENT_COMMAND; + public static String REMOVE_PUNISHMENT_COMMAND; + public static String DISABLE_CHECK_COMMAND_SYNTAX; + public static String INVALID_CHECK; + public static String CHECK_REMOVED; + public static String VIOLATIONS_COMMAND_SYNTAX; + public static String NO_LOGS; + public static String CPS_COMMAND_SYNTAX; + public static String CONNECTION_COMMAND_SYNTAX; + public static String LOGS_COMMAND_SYNTAX; + public static String NO_LOGS_FILE; + public static String LOGS_COMMAND_NO_LOGS; + public static String NO_PAGE; + public static String LOGS_COMMAND_COLOR; + public static String LOGS_COMMAND_HEADER_FOOTER; + public static String UPDATE_AVAILABLE; + public static String LATEST_VERSION; + public static String SERVER_NAME; + public static String FROZEN; + public static String LOGGED_OUT_WHILE_FROZEN; + public static String FROZE; + public static String UNFROZE; + public static String FREEZE_COMMAND_SYNTAX; + public static String UNALLOWED_CLIENT_BRAND; + public static String CLIENT_BRAND_CONSOLE_MESSAGE; + public static String FLYING_NOT_ENABLED; + public static String TOO_MANY_PACKETS; + public static String INVALID_MOVE_PACKET; + public static String IGNORE_GEYSER_PREFIX; + public static String SHUFFLE_COMMAND_SYNTAX; + public static String SHUFFLED_HOTBAR; + public static String RANDOMLY_ROTATED; + public static String ROTATE_COMMAND_SYNTAX; + public static String GHOST_BLOCK_MESSAGE; + public static String GUI_TITLE; + public static String GHOST_BLOCK_STAFF_MESSAGE; + public static String TOP_COMMAND_UNRESOLVED; + public static String EXPERIMENTAL_SYMBOL; + public static String RESET_COMMAND_SYNTAX; + public static String VIOLATIONS_RESET; + public static String UNKNOWN_COMMAND; + public static String ALERTS_SEVERITY_COLOR_6; + public static String ALERTS_SEVERITY_COLOR_7; + public static String ALERTS_SEVERITY_COLOR_8; + public static String ALERTS_SEVERITY_COLOR_9; + public static String ALERTS_SEVERITY_COLOR_10; + public static String STAFF_FROZE_BROADCAST; + public static String STAFF_UNFROZE_BROADCAST; + public static String GHOST_BLOCK_CONSOLE_MESSAGE; + public static String JDAY_LIST_HEADER_FOOTER; + public static String JDAY_LIST_FORMAT; + public static String REMOVED_FROM_JDAY; + public static String JDAY_REMOVE_COMMAND_SYNTAX; + public static String ALERTS_WEBHOOK_URL; + public static String ALERTS_WEBHOOK_AVATAR_URL; + public static String ALERTS_WEBHOOK_USERNAME; + public static String ALERTS_WEBHOOK_TITLE; + public static String ALERTS_WEBHOOK_DESCRIPTION; + public static String PUNISHMENT_WEBHOOK_URL; + public static String PUNISHMENT_WEBHOOK_AVATAR_URL; + public static String PUNISHMENT_WEBHOOK_USERNAME; + public static String PUNISHMENT_WEBHOOK_TITLE; + public static String PUNISHMENT_WEBHOOK_DESCRIPTION; + public static String PUNISH_LOGS_HEADER_FOOTER; + public static String PUNISH_LOGS_SYNTAX; + public static String TRANSACTION_KICK_MESSAGE; + public static String KEEPALIVE_KICK_MESSAGE; + public static String TRANSACTION_STAFF_ALERT_MESSAGE; + public static String KEEPALIVE_STAFF_ALERT_MESSAGE; + public static String TRANSACTION_KICK_CONSOLE_MESSAGE; + public static String KEEPALIVE_KICK_CONSOLE_MESSAGE; + public static String MAX_PING_KICK_MESSAGE; + public static String MAX_PING_KICK_STAFF_ALERT_MESSAGE; + public static String MAX_PING_KICK_CONSOLE_MESSAGE; + public static String ALERTS_WEBHOOK_THUMBNAIL; + public static String PUNISHMENT_WEBHOOK_THUMBNAIL; + public static String ALERTS_WEBHOOK_CONTENT; + public static String PUNISHMENTS_WEBHOOK_CONTENT; + public static String SENT_TEST_ALERT; + public static String UNLOADED_CHUNK_SETBACK_MESSAGE; + public static String DESYNC_KICK_MESSAGE; + public static String DESYNC_STAFF_KICK_MESSAGE; + public static String DESYNC_CONSOLE_MESSAGE; + public static long JOIN_CHECK_WAIT_TIME; + public static long TIMER_D_MAX_BALANCE; + public static long JDAY_COOLDOWN; + public static long TRANSACTION_MAX_DELAY; + public static long KEEPALIVE_MAX_DELAY; + public static boolean JOIN_MESSAGE_ENABLED; + public static boolean TOGGLE_ALERTS_ON_JOIN; + public static boolean CLIENT_BRAND_ALERTS; + public static boolean VIOLATION_RESET_MESSAGE_ENABLED; + public static boolean VIOLATION_RESET; + public static boolean ALERTS_TO_CONSOLE; + public static boolean LOG_FILE_ENABLED; + public static boolean PUNISHMENT_FILE_ENABLED; + public static boolean PER_CHECK_SEVERITY; + public static boolean CLIENT_BRAND_CONSOLE; + public static boolean ENTITY_COLLISION_FIX; + public static boolean CINEMATIC; + public static boolean DEBUG; + public static boolean CHECK_FOR_UPDATES; + public static boolean PAPERSPIGOT; + public static boolean GHOST_BLOCK_FIX; + public static boolean GHOST_BLOCK_STAFF_MESSAGE_ENABLED; + public static boolean ASYNC_ALERTS; + public static boolean ENABLE_API; + public static boolean IGNORE_GEYSER_UUIDS; + public static boolean IGNORE_GEYSER_PREFIXES; + public static boolean GHOST_BLOCK_SETBACK; + public static boolean UPDATE_CHECKER; + public static boolean KICK_ALERT_MESSAGES; + public static boolean IGNORE_GEYSER_CLIENT_BRAND; + public static boolean CLIENT_BRAND_RESOLVE; + public static boolean GHOST_BLOCK_MESSAGE_ENABLED; + public static boolean PUNISHMENT_STATISTIC_BROADCAST; + public static boolean RUN_JUDGEMENT_DAY_AT_INTERVAL; + public static boolean IGNORE_IN_JUDGEMENT_DAY; + public static boolean GHOSTHAND_A_CANCEL; + public static boolean IGNORE_VIVECRAFT; + public static boolean BOAT_FLY_A_KICKOUT; + public static boolean BOAT_FLY_B_KICKOUT; + public static boolean ENTITY_FLIGHT_A_KICKOUT; + public static boolean ENTITY_SPEED_A_KICKOUT; + public static boolean NO_SADDLE_A_KICKOUT; + public static boolean LENIENT_SCAFFOLDING; + public static boolean BAD_PACKETS_V_KICKOUT; + public static boolean SERVER_LAG_SPIKE; + public static boolean FLIGHT_A_IGNORE_GHOST_BLOCKS; + public static boolean FLIGHT_C_IGNORE_GHOST_BLOCKS; + public static boolean FLIGHT_D_IGNORE_GHOST_BLOCKS; + public static boolean GHOST_BLOCK_FIX_UPDATE_BLOCKS; + public static boolean IGNORE_FLOODGATE; + public static boolean BSTATS; + public static boolean IGNORED_1_17; + public static boolean FLIGHT_E_IGNORE_GHOST_BLOCKS; + public static boolean GHOST_BLOCK_PRINT_TO_CONSOLE; + public static boolean HOOK_MCMMO; + public static boolean HOOK_MYTHICMOBS; + public static boolean ALERTS_WEBHOOK; + public static boolean ALERTS_WEBHOOK_SERVER_NAME_FIELD; + public static boolean ALERTS_WEBHOOK_LOCATION_FIELD; + public static boolean ALERTS_WEBHOOK_CLIENT_BRAND_FIELD; + public static boolean ALERTS_WEBHOOK_INFORMATION_FIELD; + public static boolean ALERTS_WEBHOOK_DESCRIPTION_FIELD; + public static boolean ALERTS_WEBHOOK_CLIENT_VERSION_FIELD; + public static boolean PUNISHMENT_WEBHOOK; + public static boolean ALERTS_WEBHOOK_PING_TPS_FIELD; + public static boolean TRANSACTION_KICK_ENABLED; + public static boolean KEEPALIVE_KICK_ENABLED; + public static boolean GHOST_WATER_FIX; + public static boolean MAX_PING_KICK_ENABLED; + public static boolean HOOK_GSIT; + public static boolean PUNISHMENT_WEBHOOK_DESCRIPTION_FIELD; + public static boolean PUNISHMENT_WEBHOOK_SERVER_NAME_FIELD; + public static boolean PUNISHMENT_WEBHOOK_CLIENT_BRAND_FIELD; + public static boolean PUNISHMENT_WEBHOOK_CLIENT_VERSION_FIELD; + public static boolean PUNISHMENT_WEBHOOK_PING_TPS_FIELD; + public static boolean PUNISHMENT_WEBHOOK_LOCATION_FIELD; + public static boolean AIRPLACE_A_CANCEL; + public static boolean IGNORE_ALERTS_OVER_MAX_VIOLATIONS; + public static boolean CLIENT_BRAND_WHITELIST_ENABLED; + public static boolean INCOMPATABILITY_MANAGER; + public static boolean PLUGIN_MESSAGING; + public static boolean HOOK_BREWERY; + public static boolean SETBACK_LOWER_POSITION; + public static boolean VELOCITY_WORLD_BORDER; + public static boolean UNLOADED_CHUNK_SETBACK; + public static boolean DESYNC_KICK_ENABLED; + public static boolean ENTITY_CRAM_FIX_ENABLED; + public static List ALERTS_CLICK_COMMANDS; + public static List ALERTS_HOVER_MESSAGES; + public static List JDAY_COMMANDS; + public static List VERBOSE_CLICK_COMMANDS; + public static List JDAY_BROADCAST; + public static List JOIN_MESSAGE; + public static List PUNISHMENT_BROADCAST; + public static List HELP_COMMAND; + public static List BAN_COMMANDS; + public static List VERBOSE_HOVER_MESSAGES; + public static List BAN_COMMAND_BROADCAST; + public static List JDAY_STARTED_BROADCAST; + public static List PROFILE_COMMAND; + public static List ALERTS_CUSTOM_COMMANDS; + public static List CONNECTION_COMMAND; + public static List BLOCKED_CLIENT_BRANDS; + public static List CLICKALERT_COMMAND_COMMANDS; + public static List TOP_COMMAND; + public static List PUNISHMENT_STATISTIC_BROADCAST_MESSAGE; + public static List LOGGED_OUT_FROZEN_COMMANDS; + public static List JDAY_END_BROADCAST; + public static List CLIENT_BRAND_IGNORE_LIST; + public static List WHITELISTED_CLIENT_BRANDS; + public static int AUTOCLICKER_A_MAX_CPS; + public static int FASTPLACE_A_MAX_BLOCKS; + public static int ALERTS_SEVERITY_2; + public static int PUNISHMENT_STATISTIC_BROADCAST_INTERVAL; + public static int ALERTS_SEVERITY_3; + public static int ALERTS_SEVERITY_4; + public static int ALERTS_SEVERITY_5; + public static int PING_SPOOF_C_MAX_PING; + public static int SCAFFOLD_K_MAX_BLOCKS; + public static int MAX_VELOCITY_TICKS; + public static int MAX_LOGS_FILE_SIZE; + public static int IMPROBABLE_A_MAX_VIOLATIONS; + public static int IMPROBABLE_B_MAX_VIOLATIONS; + public static int IMPROBABLE_C_MAX_VIOLATIONS; + public static int IMPROBABLE_D_MAX_VIOLATIONS; + public static int PUNISHMENT_DELAY; + public static int TIMER_C_MAX_PACKETS; + public static int MAX_ALERT_VIOLATION; + public static int FLIGHT_COOLDOWN; + public static int FASTBREAK_A_MIN_DIFFERENCE; + public static int JUDGEMENT_DAY_INTERVAL; + public static int MIN_TICKS_EXISTED; + public static int DESYNC_MAX_TICKS; + public static int GHOST_BLOCK_MIN_TICKS; + public static int ALERTS_SEVERITY_6; + public static int ALERTS_SEVERITY_7; + public static int ALERTS_SEVERITY_8; + public static int ALERTS_SEVERITY_9; + public static int ALERTS_SEVERITY_10; + public static int IMPROBABLE_E_MAX_VIOLATIONS; + public static int IMPROBABLE_F_MAX_SCAFFOLD_VIOLATIONS; + public static int MAX_UNLOADED_CHUNK_TICKS; + public static int ALERTS_WEBHOOK_COLOR_R; + public static int ALERTS_WEBHOOK_COLOR_G; + public static int ALERTS_WEBHOOK_COLOR_B; + public static int PUNISHMENT_WEBHOOK_COLOR_R; + public static int PUNISHMENT_WEBHOOK_COLOR_G; + public static int PUNISHMENT_WEBHOOK_COLOR_B; + public static int MAX_PING; + public static int MAX_PING_KICK_TICKS; + public static int IGNORE_ALERTS_OVER_MAX_VIOLATIONS_AMOUNT; + public static int FASTPLACE_B_MAX_BLOCKS; + public static int ENTITY_CRAM_FIX_AMOUNT; + public static int ENTITY_CRAM_FIX_EXEMPT_TICKS; + public static double BOAT_FLY_A_MAX_SPEED; + public static double ELYTRA_A_MAX_SPEED; + public static double REACH_A_MAX_REACH; + public static double HITBOX_A_MAX_ANGLE; + public static double HITBOX_B_MAX_ANGLE; + public static double ENTITY_SPEED_A_MAX_SPEED; + public static double TIMER_A_MAX_SPEED; + public static double REACH_B_MAX_REACH; + public static double INTERACT_A_MAX_DISTANCE; + public static double INTERACT_B_MAX_DISTANCE; + public static double TIMER_B_MIN_SPEED; + public static double SPEED_B_MIN_DIFFERENCE; + public static double SPEED_C_MIN_DIFFERENCE; + public static double SPEED_D_MIN_DIFFERENCE; + public static double ELYTRA_L_MIN_DIFFERENCE; + public static double ELYTRA_M_MIN_DIFFERENCE; + public static double GHOST_BLOCK_MAX_BUFFER; + public static double GHOST_BLOCK_BUFFER_DECAY; + public static double AUTOCLICKER_T_MIN_KURTOSIS; + public static double GHOST_BLOCK_MIN_TPS; + private static final String fileName = "config"; + private static CommentedConfiguration config; + private static File file; + + public static void save() { + try { + Config.config.save(Config.file); + } + catch (final Exception exception) { + final File newFile = new File(Vulcan.INSTANCE.getPlugin().getDataFolder(), "config.broken." + new Date().getTime()); + Vulcan.INSTANCE.getPlugin().getLogger().log(Level.SEVERE, "Could not save: config.yml"); + Vulcan.INSTANCE.getPlugin().getLogger().log(Level.SEVERE, "Regenerating file and renaming the current file to: " + newFile.getName()); + Vulcan.INSTANCE.getPlugin().getLogger().log(Level.SEVERE, "You can try fixing the file with a yaml parser online!"); + Config.file.renameTo(newFile); + initialize(); + } + } + + public static void reload() { + try { + Config.config.load(Config.file); + } + catch (final Exception exception) { + final File newFile = new File(Vulcan.INSTANCE.getPlugin().getDataFolder(), "config.broken." + new Date().getTime()); + Vulcan.INSTANCE.getPlugin().getLogger().log(Level.SEVERE, "Could not save: config.yml"); + Vulcan.INSTANCE.getPlugin().getLogger().log(Level.SEVERE, "Regenerating file and renaming the current file to: " + newFile.getName()); + Vulcan.INSTANCE.getPlugin().getLogger().log(Level.SEVERE, "You can try fixing the file with a yaml parser online!"); + Config.file.renameTo(newFile); + initialize(); + } + } + + public static void initialize() { + if (!Vulcan.INSTANCE.getPlugin().getDataFolder().exists()) { + Vulcan.INSTANCE.getPlugin().getDataFolder().mkdir(); + } + Config.file = new File(Vulcan.INSTANCE.getPlugin().getDataFolder(), "config.yml"); + if (!Config.file.exists()) { + Config.file.getParentFile().mkdirs(); + copy(Vulcan.INSTANCE.getPlugin().getResource("config.yml"), Config.file); + } + Config.config = CommentedConfiguration.loadConfiguration(Config.file); + try { + Config.config.syncWithConfig(Config.file, Vulcan.INSTANCE.getPlugin().getResource("config.yml"), "NONE"); + } + catch (final Exception ex) {} + } + + private static void copy(final InputStream in, final File file) { + try { + final OutputStream out = new FileOutputStream(file); + final byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + out.close(); + in.close(); + } + catch (final Exception exception) { + exception.printStackTrace(); + } + } + + public static void updateConfig() { + try { + Config.PREFIX = getString("prefix"); + Config.ALERTS_FORMAT = getString("alerts.format"); + Config.NO_PERMISSION = getString("messages.no-permission"); + Config.UNLOADED_CHUNK_SETBACK = getBoolean("unloaded-chunks.setback-enabled"); + Config.UNLOADED_CHUNK_SETBACK_MESSAGE = getString("unloaded-chunks.message"); + Config.MAX_UNLOADED_CHUNK_TICKS = getInt("unloaded-chunks.max-ticks"); + Config.DESYNC_KICK_ENABLED = getBoolean("connection.desync.kick-enabled"); + Config.DESYNC_MAX_TICKS = getInt("connection.desync.max-ticks"); + Config.DESYNC_KICK_MESSAGE = getString("connection.desync.kick-message"); + Config.DESYNC_STAFF_KICK_MESSAGE = getString("connection.desync.staff-alert-message"); + Config.DESYNC_CONSOLE_MESSAGE = getString("connection.desync.console-message"); + Config.ALERTS_ENABLED = getString("alerts.toggled-on-message"); + Config.ALERTS_DISABLED = getString("alerts.toggled-off-message"); + Config.ALERTS_HOVER_MESSAGES = getStringList("alerts.hover-message"); + Config.ALERTS_CLICK_COMMANDS = getStringList("alerts.click-commands"); + Config.CANT_EXECUTE_FROM_CONSOLE = getString("messages.cant-execute-from-console"); + Config.JDAY_COMMANDS = getStringList("judgement-days.commands"); + Config.JDAY_BROADCAST = getStringList("judgement-days.broadcast"); + Config.JDAY_END_BROADCAST = getStringList("judgement-days.ended-broadcast"); + Config.JOIN_MESSAGE_ENABLED = getBoolean("join-message.enabled"); + Config.JOIN_MESSAGE = getStringList("join-message.message"); + Config.TOGGLE_ALERTS_ON_JOIN = getBoolean("settings.toggle-alerts-on-join"); + Config.PUNISHMENT_MESSAGE = getString("punishments.message"); + Config.PUNISHMENT_BROADCAST = getStringList("punishments.broadcast"); + Config.HELP_COMMAND = getStringList("commands.help"); + Config.JDAY_LIST_HEADER_FOOTER = getString("commands.jday.list-header-footer"); + Config.PUNISH_LOGS_HEADER_FOOTER = getString("commands.punishlogs.header-footer"); + Config.JDAY_LIST_FORMAT = getString("commands.jday.list-format"); + Config.GHOST_WATER_FIX = getBoolean("ghost-blocks-fix.ghost-water-fix"); + Config.SETBACK_LOWER_POSITION = getBoolean("settings.dont-setback-lower-positions"); + Config.TRANSACTION_KICK_MESSAGE = getString("connection.transaction.kick-message"); + Config.KEEPALIVE_KICK_MESSAGE = getString("connection.keepalive.kick-message"); + Config.MAX_PING_KICK_MESSAGE = getString("connection.max-ping.kick-message"); + Config.TRANSACTION_KICK_ENABLED = getBoolean("connection.transaction.kick-enabled"); + Config.KEEPALIVE_KICK_ENABLED = getBoolean("connection.keepalive.kick-enabled"); + Config.MAX_PING_KICK_ENABLED = getBoolean("connection.max-ping.kick-enabled"); + Config.MAX_PING = getInt("connection.max-ping.max-ping"); + Config.VELOCITY_WORLD_BORDER = getBoolean("settings.velocity-world-border"); + Config.INCOMPATABILITY_MANAGER = getBoolean("settings.incompatability-manager"); + Config.PLUGIN_MESSAGING = getBoolean("settings.plugin-messaging"); + Config.MAX_PING_KICK_TICKS = getInt("connection.max-ping.max-ticks"); + Config.TRANSACTION_STAFF_ALERT_MESSAGE = getString("connection.transaction.staff-alert-message"); + Config.KEEPALIVE_STAFF_ALERT_MESSAGE = getString("connection.keepalive.staff-alert-message"); + Config.MAX_PING_KICK_STAFF_ALERT_MESSAGE = getString("connection.max-ping.staff-alert-message"); + Config.TRANSACTION_KICK_CONSOLE_MESSAGE = getString("connection.transaction.console-message"); + Config.MAX_PING_KICK_CONSOLE_MESSAGE = getString("connection.max-ping.console-message"); + Config.KEEPALIVE_KICK_CONSOLE_MESSAGE = getString("connection.keepalive.console-message"); + Config.TRANSACTION_MAX_DELAY = getLong("connection.transaction.max-delay"); + Config.KEEPALIVE_MAX_DELAY = getLong("connection.keepalive.max-delay"); + Config.PUNISHMENT_WEBHOOK = getBoolean("discord-webhook.punishments.enabled"); + Config.PUNISHMENT_WEBHOOK_URL = getString("discord-webhook.punishments.url"); + Config.PUNISHMENT_WEBHOOK_AVATAR_URL = getString("discord-webhook.punishments.avatar"); + Config.PUNISHMENT_WEBHOOK_THUMBNAIL = getString("discord-webhook.punishments.thumbnail"); + Config.PUNISHMENT_WEBHOOK_COLOR_R = getInt("discord-webhook.punishments.color-r"); + Config.PUNISHMENT_WEBHOOK_COLOR_G = getInt("discord-webhook.punishments.color-g"); + Config.PUNISHMENT_WEBHOOK_COLOR_B = getInt("discord-webhook.punishments.color-b"); + Config.PUNISHMENT_WEBHOOK_USERNAME = getString("discord-webhook.punishments.username"); + Config.PUNISHMENT_WEBHOOK_TITLE = getString("discord-webhook.punishments.title"); + Config.IGNORE_ALERTS_OVER_MAX_VIOLATIONS = getBoolean("settings.ignore-alerts-over-max-violations"); + Config.IGNORE_ALERTS_OVER_MAX_VIOLATIONS_AMOUNT = getInt("settings.ignore-alerts-over-max-violations-amount"); + Config.PUNISHMENT_WEBHOOK_DESCRIPTION = getString("discord-webhook.punishments.description"); + Config.PUNISH_LOGS_SYNTAX = getString("messages.punishlogs-syntax"); + Config.ALERTS_WEBHOOK = getBoolean("discord-webhook.alerts.enabled"); + Config.ALERTS_WEBHOOK_URL = getString("discord-webhook.alerts.url"); + Config.ALERTS_WEBHOOK_AVATAR_URL = getString("discord-webhook.alerts.avatar"); + Config.ALERTS_WEBHOOK_THUMBNAIL = getString("discord-webhook.alerts.thumbnail"); + Config.ALERTS_WEBHOOK_COLOR_R = getInt("discord-webhook.alerts.color-r"); + Config.ALERTS_WEBHOOK_COLOR_G = getInt("discord-webhook.alerts.color-g"); + Config.ALERTS_WEBHOOK_COLOR_B = getInt("discord-webhook.alerts.color-b"); + Config.ALERTS_WEBHOOK_USERNAME = getString("discord-webhook.alerts.username"); + Config.ALERTS_WEBHOOK_TITLE = getString("discord-webhook.alerts.title"); + Config.ALERTS_WEBHOOK_DESCRIPTION = getString("discord-webhook.alerts.description"); + Config.ALERTS_WEBHOOK_SERVER_NAME_FIELD = getBoolean("discord-webhook.alerts.server-name-field"); + Config.ALERTS_WEBHOOK_CONTENT = getString("discord-webhook.alerts.content"); + Config.PUNISHMENTS_WEBHOOK_CONTENT = getString("discord-webhook.punishments.content"); + Config.PUNISHMENT_WEBHOOK_SERVER_NAME_FIELD = getBoolean("discord-webhook.punishments.server-name-field"); + Config.ALERTS_WEBHOOK_LOCATION_FIELD = getBoolean("discord-webhook.alerts.location-field"); + Config.PUNISHMENT_WEBHOOK_LOCATION_FIELD = getBoolean("discord-webhook.punishments.location-field"); + Config.ALERTS_WEBHOOK_CLIENT_BRAND_FIELD = getBoolean("discord-webhook.alerts.client-brand-field"); + Config.PUNISHMENT_WEBHOOK_CLIENT_BRAND_FIELD = getBoolean("discord-webhook.punishments.client-brand-field"); + Config.ALERTS_WEBHOOK_INFORMATION_FIELD = getBoolean("discord-webhook.alerts.information-field"); + Config.ALERTS_WEBHOOK_DESCRIPTION_FIELD = getBoolean("discord-webhook.alerts.description-field"); + Config.PUNISHMENT_WEBHOOK_DESCRIPTION_FIELD = getBoolean("discord-webhook.punishments.description-field"); + Config.ALERTS_WEBHOOK_CLIENT_VERSION_FIELD = getBoolean("discord-webhook.alerts.client-version-field"); + Config.PUNISHMENT_WEBHOOK_CLIENT_VERSION_FIELD = getBoolean("discord-webhook.punishments.client-version-field"); + Config.ALERTS_WEBHOOK_PING_TPS_FIELD = getBoolean("discord-webhook.alerts.ping-tps-field"); + Config.PUNISHMENT_WEBHOOK_PING_TPS_FIELD = getBoolean("discord-webhook.punishments.ping-tps-field"); + Config.JDAY_REMOVE_COMMAND_SYNTAX = getString("messages.jday-remove-syntax"); + Config.BAN_COMMAND_SYNTAX = getString("messages.ban-command-syntax"); + Config.BAN_COMMANDS = getStringList("commands.ban.commands"); + Config.BAN_COMMAND_BROADCAST = getStringList("commands.ban.broadcast"); + Config.RELOAD_SUCCESS = getString("messages.reload-success"); + Config.KB_COMMAND_SYNTAX = getString("messages.kb-command-syntax"); + Config.INVALID_TARGET = getString("messages.invalid-target"); + Config.KB_TEST_SUCCESS = getString("messages.kb-test-success"); + Config.JDAY_COMMAND_SYNTAX = getString("messages.jday-command-syntax"); + Config.JDAY_NO_PENDING_BANS = getString("messages.jday-no-pending-bans"); + Config.JDAY_STARTED_BROADCAST = getStringList("judgement-days.started-broadcast"); + Config.JDAY_ADDED_TO_LIST = getString("messages.jday-added-to-list"); + Config.RESET_COMMAND = getString("messages.reset-command"); + Config.SERVER_LAG_SPIKE = getBoolean("settings.server-lag-spike"); + Config.PROFILE_COMMAND_SYNTAX = getString("messages.profile-command-syntax"); + Config.PROFILE_COMMAND = getStringList("commands.profile"); + Config.CLIENT_BRAND_ALERTS = getBoolean("client-brand-alerts.enabled"); + Config.CLIENT_BRAND_ALERT_MESSAGE = getString("client-brand-alerts.message"); + Config.CLIENT_BRAND_RESOLVE = getBoolean("client-brand-alerts.resolve"); + Config.REMOVED_FROM_JDAY = getString("messages.removed-from-jday"); + Config.VERBOSE_ENABLED = getString("verbose.toggled-on-message"); + Config.VERBOSE_DISABLED = getString("verbose.toggled-off-message"); + Config.VERBOSE_HOVER_MESSAGES = getStringList("verbose.hover-message"); + Config.VERBOSE_CLICK_COMMANDS = getStringList("verbose.click-commands"); + Config.VERBOSE_FORMAT = getString("verbose.format"); + Config.VIOLATION_RESET = getBoolean("violation-reset.enabled"); + Config.VIOLATION_RESET_MESSAGE_ENABLED = getBoolean("violation-reset.message-enabled"); + Config.VIOLATION_RESET_MESSAGE = getString("violation-reset.message"); + Config.ALERTS_TO_CONSOLE = getBoolean("alerts.print-to-console"); + Config.ALERTS_CONSOLE_FORMAT = getString("alerts.console-format"); + Config.LOG_FILE_ENABLED = getBoolean("log-file.enabled"); + Config.LOG_FILE_ALERT_MESSAGE = getString("log-file.alert-message"); + Config.LOG_FILE_PUNISHMENT_MESSAGE = getString("log-file.punishment-message"); + Config.PUNISHMENT_FILE_ENABLED = getBoolean("punishment-file.enabled"); + Config.AUTOCLICKER_A_MAX_CPS = getInt("checks.combat.autoclicker.a.max-cps"); + Config.AUTOCLICKER_T_MIN_KURTOSIS = getInt("checks.combat.autoclicker.t.min-kurtosis"); + Config.CLICKALERT_COMMAND_COMMANDS = getStringList("alerts.click-alert-command-commands"); + Config.FASTPLACE_A_MAX_BLOCKS = getInt("checks.player.fastplace.a.max-blocks"); + Config.FASTPLACE_B_MAX_BLOCKS = getInt("checks.player.fastplace.b.max-blocks"); + Config.AIRPLACE_A_CANCEL = getBoolean("checks.player.airplace.a.cancel"); + Config.IGNORE_VIVECRAFT = getBoolean("settings.ignore-vivecraft"); + Config.BOAT_FLY_A_KICKOUT = getBoolean("checks.movement.boatfly.a.kick-out"); + Config.BOAT_FLY_B_KICKOUT = getBoolean("checks.movement.boatfly.b.kick-out"); + Config.ENTITY_SPEED_A_KICKOUT = getBoolean("checks.movement.entityspeed.a.kick-out"); + Config.ENTITY_FLIGHT_A_KICKOUT = getBoolean("checks.movement.entityflight.a.kick-out"); + Config.SPEED_B_MIN_DIFFERENCE = getDouble("checks.movement.speed.b.min-difference"); + Config.SPEED_C_MIN_DIFFERENCE = getDouble("checks.movement.speed.c.min-difference"); + Config.SPEED_D_MIN_DIFFERENCE = getDouble("checks.movement.speed.d.min-difference"); + Config.FLIGHT_A_IGNORE_GHOST_BLOCKS = getBoolean("checks.movement.flight.a.ignore-ghost-blocks"); + Config.FLIGHT_C_IGNORE_GHOST_BLOCKS = getBoolean("checks.movement.flight.c.ignore-ghost-blocks"); + Config.FLIGHT_D_IGNORE_GHOST_BLOCKS = getBoolean("checks.movement.flight.d.ignore-ghost-blocks"); + Config.FLIGHT_E_IGNORE_GHOST_BLOCKS = getBoolean("checks.movement.flight.e.ignore-ghost-blocks"); + Config.ELYTRA_L_MIN_DIFFERENCE = getDouble("checks.movement.elytra.l.min-difference"); + Config.ELYTRA_M_MIN_DIFFERENCE = getDouble("checks.movement.elytra.m.min-difference"); + Config.NO_SADDLE_A_KICKOUT = getBoolean("checks.movement.nosaddle.a.kick-out"); + Config.NO_SADDLE_A_KICKOUT = getBoolean("checks.player.badpackets.v.kick-out"); + Config.BOAT_FLY_A_MAX_SPEED = getDouble("checks.movement.boatfly.a.max-speed"); + Config.ELYTRA_A_MAX_SPEED = getDouble("checks.movement.elytra.a.max-speed"); + Config.REACH_A_MAX_REACH = getDouble("checks.combat.reach.a.max-reach"); + Config.REACH_B_MAX_REACH = getDouble("checks.combat.reach.b.max-reach"); + Config.IGNORE_GEYSER_PREFIXES = getBoolean("settings.ignore-geyser-prefixes"); + Config.IGNORE_GEYSER_PREFIX = getString("settings.ignore-geyser-prefix"); + Config.SCAFFOLD_K_MAX_BLOCKS = getInt("checks.player.scaffold.k.max-blocks"); + Config.HITBOX_A_MAX_ANGLE = getDouble("checks.combat.hitbox.a.max-angle"); + Config.HITBOX_B_MAX_ANGLE = getDouble("checks.combat.hitbox.b.max-angle"); + Config.TIMER_B_MIN_SPEED = getDouble("checks.player.timer.b.min-speed"); + Config.INTERACT_A_MAX_DISTANCE = getDouble("checks.player.interact.a.max-distance"); + Config.INTERACT_B_MAX_DISTANCE = getDouble("checks.player.interact.b.max-distance"); + Config.ENTITY_SPEED_A_MAX_SPEED = getDouble("checks.movement.entityspeed.a.max-speed"); + Config.IMPROBABLE_A_MAX_VIOLATIONS = getInt("checks.player.improbable.a.max-combat-violations"); + Config.IMPROBABLE_B_MAX_VIOLATIONS = getInt("checks.player.improbable.b.max-movement-violations"); + Config.IMPROBABLE_C_MAX_VIOLATIONS = getInt("checks.player.improbable.c.max-player-violations"); + Config.IMPROBABLE_D_MAX_VIOLATIONS = getInt("checks.player.improbable.d.max-autoclicker-violations"); + Config.IMPROBABLE_E_MAX_VIOLATIONS = getInt("checks.player.improbable.e.max-total-violations"); + Config.IMPROBABLE_F_MAX_SCAFFOLD_VIOLATIONS = getInt("checks.player.improbable.f.max-scaffold-violations"); + Config.GHOSTHAND_A_CANCEL = getBoolean("checks.player.ghosthand.a.cancel"); + Config.FASTBREAK_A_MIN_DIFFERENCE = getInt("checks.player.fastbreak.a.min-difference"); + Config.ALERTS_CUSTOM_COMMANDS = getStringList("alerts.custom-commands"); + Config.TIMER_A_MAX_SPEED = getDouble("checks.player.timer.a.max-speed"); + Config.TIMER_C_MAX_PACKETS = getInt("checks.player.timer.c.max-packets"); + Config.TIMER_D_MAX_BALANCE = getLong("checks.player.timer.d.max-balance"); + Config.IGNORE_GEYSER_UUIDS = getBoolean("settings.ignore-geyser-uuids"); + Config.IGNORED_1_17 = getBoolean("settings.ignore-1-17"); + Config.ALERTS_SEVERITY_2 = getInt("alerts.severity.violations.2"); + Config.ALERTS_SEVERITY_3 = getInt("alerts.severity.violations.3"); + Config.ALERTS_SEVERITY_4 = getInt("alerts.severity.violations.4"); + Config.ALERTS_SEVERITY_5 = getInt("alerts.severity.violations.5"); + Config.ALERTS_SEVERITY_6 = getInt("alerts.severity.violations.6"); + Config.ALERTS_SEVERITY_7 = getInt("alerts.severity.violations.7"); + Config.ALERTS_SEVERITY_8 = getInt("alerts.severity.violations.8"); + Config.ALERTS_SEVERITY_9 = getInt("alerts.severity.violations.9"); + Config.ALERTS_SEVERITY_10 = getInt("alerts.severity.violations.10"); + Config.ALERTS_SEVERITY_COLOR_1 = getString("alerts.severity.colors.1"); + Config.ALERTS_SEVERITY_COLOR_2 = getString("alerts.severity.colors.2"); + Config.ALERTS_SEVERITY_COLOR_3 = getString("alerts.severity.colors.3"); + Config.ALERTS_SEVERITY_COLOR_4 = getString("alerts.severity.colors.4"); + Config.ALERTS_SEVERITY_COLOR_5 = getString("alerts.severity.colors.5"); + Config.ALERTS_SEVERITY_COLOR_6 = getString("alerts.severity.colors.6"); + Config.ALERTS_SEVERITY_COLOR_7 = getString("alerts.severity.colors.7"); + Config.ALERTS_SEVERITY_COLOR_8 = getString("alerts.severity.colors.8"); + Config.ALERTS_SEVERITY_COLOR_9 = getString("alerts.severity.colors.9"); + Config.ALERTS_SEVERITY_COLOR_10 = getString("alerts.severity.colors.10"); + Config.PER_CHECK_SEVERITY = getBoolean("settings.per-check-severities"); + Config.PING_SPOOF_C_MAX_PING = getInt("checks.player.pingspoof.c.max-ping"); + Config.ENTITY_COLLISION_FIX = getBoolean("settings.entity-collision-fix"); + Config.CINEMATIC = getBoolean("settings.cinematic"); + Config.CPS_COMMAND = getString("commands.cps"); + Config.DEBUG = getBoolean("settings.debug"); + Config.SENT_TEST_ALERT = getString("messages.sent-test-alert"); + Config.NO_NEXT_PAGE = getString("messages.no-next-page"); + Config.NO_PREVIOUS_PAGE = getString("messages.no-previous-page"); + Config.ENABLED_ALL_CHECKS = getString("messages.enabled-all-checks"); + Config.DISABLED_ALL_CHECKS = getString("messages.disabled-all-checks"); + Config.ENABLED_ALL_PUNISHMENTS = getString("messages.enabled-all-punishments"); + Config.DISABLED_ALL_PUNISHMENTS = getString("messages.disabled-all-punishments"); + Config.ENABLED_CHECK = getString("messages.enabled-check"); + Config.DISABLED_CHECK = getString("messages.disabled-check"); + Config.ENABLED_PUNISHMENT = getString("messages.enabled-punishment"); + Config.DISABLED_PUNISHMENT = getString("messages.disabled-punishment"); + Config.ENABLED_HOTBAR_SHUFFLE = getString("messages.enabled-hotbar-shuffle"); + Config.DISABLED_HOTBAR_SHUFFLE = getString("messages.disabled-hotbar-shuffle"); + Config.ENABLED_RANDOM_ROTATION = getString("messages.enabled-random-rotation"); + Config.DISABLED_RANDOM_ROTATION = getString("messages.disabled-random-rotation"); + Config.ENABLED_BROADCAST_PUNISHMENT = getString("messages.enabled-broadcast-punishment"); + Config.DISABLED_BROADCAST_PUNISHMENT = getString("messages.disabled-broadcast-punishment"); + Config.MUST_BE_AN_INTEGER = getString("messages.must-be-an-integer"); + Config.MUST_BE_POSITIVE = getString("messages.must-be-positive"); + Config.SET_MAX_BUFFER = getString("messages.set-max-buffer"); + Config.SET_HOTBAR_SHUFFLE_MINIMUM_VIOLATIONS = getString("messages.set-hotbar-shuffle-minimum-violations"); + Config.SET_HOTBAR_SHUFFLE_INTERVAL = getString("messages.set-hotbar-interval"); + Config.SET_RANDOM_ROTATION_MINIMUM_VIOLATIONS = getString("messages.set-random-rotation-minimum-violations"); + Config.SET_RANDOM_ROTATION_INTERVAL = getString("messages.set-random-rotation-interval"); + Config.SET_ALERT_INTERVAL = getString("messages.set-alert-interval"); + Config.MUST_BE_NUMBER = getString("messages.must-be-number"); + Config.SET_BUFFER_MULTIPLE = getString("messages.set-buffer-multiple"); + Config.SET_BUFFER_DECAY = getString("messages.set-buffer-decay"); + Config.SET_MAX_VIOLATIONS = getString("messages.set-max-violations"); + Config.SET_MINIMUM_VIOLATIONS_TO_ALERT = getString("messages.set-minimum-violations-to-alert"); + Config.SET_MAXIMUM_PING = getString("messages.set-maximum-ping"); + Config.SET_MINIMUM_TPS = getString("messages.set-minimum-tps"); + Config.REMOVED_PUNISHMENT_COMMAND = getString("messages.removed-punishment-command"); + Config.INVALID_INDEX_NUMBER = getString("messages.invalid-index-number"); + Config.STOPPED_EDITING_PUNISHMENT_COMMANDS = getString("messages.stopped-editing-punishment-commands"); + Config.ADDED_PUNISHMENT_COMMAND = getString("messages.added-punishment-command"); + Config.ENTER_PUNISHMENT_COMMAND = getString("messages.enter-punishment-command"); + Config.REMOVE_PUNISHMENT_COMMAND = getString("messages.remove-punishment-command"); + Config.DISABLE_CHECK_COMMAND_SYNTAX = getString("messages.disable-check-command-syntax"); + Config.INVALID_CHECK = getString("messages.invalid-check"); + Config.CHECK_REMOVED = getString("messages.check-removed"); + Config.VIOLATIONS_COMMAND_SYNTAX = getString("messages.violations-command-syntax"); + Config.NO_LOGS = getString("messages.no-logs"); + Config.CPS_COMMAND_SYNTAX = getString("messages.cps-command-syntax"); + Config.CONNECTION_COMMAND_SYNTAX = getString("messages.connection-command-syntax"); + Config.CONNECTION_COMMAND = getStringList("commands.connection"); + Config.LOGS_COMMAND_SYNTAX = getString("messages.logs-command-syntax"); + Config.NO_LOGS_FILE = getString("messages.no-logs-file"); + Config.LOGS_COMMAND_NO_LOGS = getString("messages.logs-command-no-logs"); + Config.NO_PAGE = getString("messages.no-page"); + Config.LOGS_COMMAND_COLOR = getString("commands.logs.color"); + Config.LOGS_COMMAND_HEADER_FOOTER = getString("commands.logs.header-footer"); + Config.CHECK_FOR_UPDATES = getBoolean("settings.check-for-updates"); + Config.UPDATE_AVAILABLE = getString("messages.update-available"); + Config.IGNORE_FLOODGATE = getBoolean("settings.ignore-floodgate"); + Config.LATEST_VERSION = getString("messages.latest-version"); + Config.PAPERSPIGOT = getBoolean("settings.paperspigot"); + Config.BSTATS = getBoolean("settings.bstats"); + Config.CLIENT_BRAND_IGNORE_LIST = getStringList("client-brand-alerts.ignore-alerts-list"); + Config.MAX_VELOCITY_TICKS = getInt("settings.max-velocity-ticks"); + Config.MAX_LOGS_FILE_SIZE = getInt("settings.max-logs-file-size"); + Config.SERVER_NAME = getString("settings.server-name"); + Config.FROZEN = getString("messages.frozen"); + Config.LOGGED_OUT_WHILE_FROZEN = getString("messages.logged-out-while-frozen"); + Config.FROZE = getString("messages.froze"); + Config.UNFROZE = getString("messages.unfroze"); + Config.FREEZE_COMMAND_SYNTAX = getString("messages.freeze-command-syntax"); + Config.BLOCKED_CLIENT_BRANDS = getStringList("client-brand-alerts.blocked-client-brands"); + Config.UNALLOWED_CLIENT_BRAND = getString("client-brand-alerts.unallowed-client-brand-kick-message"); + Config.ASYNC_ALERTS = getBoolean("settings.async-alerts"); + Config.ENABLE_API = getBoolean("settings.enable-api"); + Config.UPDATE_CHECKER = getBoolean("settings.update-checker"); + Config.KICK_ALERT_MESSAGES = getBoolean("kick-alert-messages.enabled"); + Config.FLYING_NOT_ENABLED = getString("kick-alert-messages.messages.flying-not-enabled"); + Config.TOO_MANY_PACKETS = getString("kick-alert-messages.messages.too-many-packets"); + Config.INVALID_MOVE_PACKET = getString("kick-alert-messages.messages.invalid-move-packet"); + Config.PUNISHMENT_DELAY = getInt("settings.punishment-delay"); + Config.IGNORE_GEYSER_CLIENT_BRAND = getBoolean("settings.ignore-flags-geyser-client-brand"); + Config.JOIN_CHECK_WAIT_TIME = getLong("settings.join-check-wait-time"); + Config.MIN_TICKS_EXISTED = getInt("settings.min-ticks-existed"); + Config.MAX_ALERT_VIOLATION = getInt("settings.max-alert-violation"); + Config.SHUFFLE_COMMAND_SYNTAX = getString("messages.shuffle-command-syntax"); + Config.SHUFFLED_HOTBAR = getString("messages.shuffled-hotbar"); + Config.ROTATE_COMMAND_SYNTAX = getString("messages.rotate-command-syntax"); + Config.RANDOMLY_ROTATED = getString("messages.randomly-rotated"); + Config.TOP_COMMAND = getStringList("commands.top"); + Config.GHOST_BLOCK_FIX = getBoolean("ghost-blocks-fix.enabled"); + Config.GHOST_BLOCK_MIN_TPS = getDouble("ghost-blocks-fix.minimum-tps"); + Config.GHOST_BLOCK_MAX_BUFFER = getDouble("ghost-blocks-fix.buffer.max"); + Config.GHOST_BLOCK_BUFFER_DECAY = getDouble("ghost-blocks-fix.buffer.decay"); + Config.GHOST_BLOCK_MESSAGE = getString("ghost-blocks-fix.message"); + Config.GHOST_BLOCK_MIN_TICKS = getInt("ghost-blocks-fix.ticks"); + Config.GHOST_BLOCK_FIX_UPDATE_BLOCKS = getBoolean("ghost-blocks-fix.update-blocks"); + Config.GUI_TITLE = getString("gui.title"); + Config.FLIGHT_COOLDOWN = getInt("settings.flight-cooldown"); + Config.GHOST_BLOCK_MESSAGE_ENABLED = getBoolean("ghost-blocks-fix.message-enabled"); + Config.GHOST_BLOCK_STAFF_MESSAGE_ENABLED = getBoolean("ghost-blocks-fix.staff-message-enabled"); + Config.GHOST_BLOCK_STAFF_MESSAGE = getString("ghost-blocks-fix.staff-message"); + Config.GHOST_BLOCK_SETBACK = getBoolean("ghost-blocks-fix.setback"); + Config.GHOST_BLOCK_PRINT_TO_CONSOLE = getBoolean("ghost-blocks-fix.print-to-console"); + Config.CLIENT_BRAND_CONSOLE = getBoolean("client-brand-alerts.console"); + Config.CLIENT_BRAND_CONSOLE_MESSAGE = getString("client-brand-alerts.console-message"); + Config.TOP_COMMAND_UNRESOLVED = getString("settings.top-command-unresolved"); + Config.JDAY_COOLDOWN = getLong("judgement-days.cooldown"); + Config.PUNISHMENT_STATISTIC_BROADCAST = getBoolean("punishment-statistics-broadcast.enabled"); + Config.PUNISHMENT_STATISTIC_BROADCAST_MESSAGE = getStringList("punishment-statistics-broadcast.broadcast"); + Config.PUNISHMENT_STATISTIC_BROADCAST_INTERVAL = getInt("punishment-statistics-broadcast.interval"); + Config.RUN_JUDGEMENT_DAY_AT_INTERVAL = getBoolean("judgement-days.run-at-interval"); + Config.JUDGEMENT_DAY_INTERVAL = getInt("judgement-days.interval"); + Config.LOGGED_OUT_FROZEN_COMMANDS = getStringList("freeze.logged-out-while-frozen-commands"); + Config.EXPERIMENTAL_SYMBOL = getString("alerts.experimental-symbol"); + Config.IGNORE_IN_JUDGEMENT_DAY = getBoolean("settings.ignore-if-in-judgement-day"); + Config.RESET_COMMAND_SYNTAX = getString("messages.reset-command-syntax"); + Config.VIOLATIONS_RESET = getString("messages.violations-reset"); + Config.UNKNOWN_COMMAND = getString("messages.unknown-command"); + Config.STAFF_FROZE_BROADCAST = getString("messages.froze-staff-broadcast"); + Config.STAFF_UNFROZE_BROADCAST = getString("messages.unfroze-staff-broadcast"); + Config.LENIENT_SCAFFOLDING = getBoolean("settings.lenient-scaffolding"); + Config.GHOST_BLOCK_CONSOLE_MESSAGE = getString("ghost-blocks-fix.console-message"); + Config.ENTITY_COLLISION_FIX = getBoolean("settings.entity-collision"); + Config.HOOK_MCMMO = getBoolean("settings.hook-mcmmo"); + Config.HOOK_MYTHICMOBS = getBoolean("settings.hook-mythicmobs"); + Config.HOOK_GSIT = getBoolean("settings.hook-gsit"); + Config.HOOK_BREWERY = getBoolean("settings.hook-brewery"); + Config.WHITELISTED_CLIENT_BRANDS = getStringList("client-brand-alerts.whitelisted-client-brands"); + Config.CLIENT_BRAND_WHITELIST_ENABLED = getBoolean("client-brand-alerts.whitelist-enabled"); + Config.ENTITY_CRAM_FIX_ENABLED = getBoolean("settings.entity-cram-fix-enabled"); + Config.ENTITY_CRAM_FIX_AMOUNT = getInt("settings.entity-cram-entities-amount"); + Config.ENTITY_CRAM_FIX_EXEMPT_TICKS = getInt("settings.entity-cram-exempt-ticks"); + CacheUtil.updateCheckValues(); + } + catch (final Exception e) { + Bukkit.getLogger().severe("Error while loading Vulcan's configuration file!"); + e.printStackTrace(); + } + } + + public static boolean getBoolean(final String string) { + return Config.config.getBoolean(string); + } + + public static String getString(final String string) { + return Config.config.getString(string); + } + + public static int getInt(final String string) { + return Config.config.getInt(string); + } + + public static double getDouble(final String string) { + return Config.config.getDouble(string); + } + + public static long getLong(final String string) { + return Config.config.getLong(string); + } + + public static List getStringList(final String string) { + return Config.config.getStringList(string); + } + + public static boolean isString(final String string) { + return Config.config.isString(string); + } + + public static Color getColor(final String string) { + return Config.config.getColor(string); + } + + public static boolean isColor(final String string) { + return Config.config.isColor(string); + } + + public static void setValue(final String path, final Object object) { + Vulcan.INSTANCE.getPlugin().getConfig().set(path, object); + Vulcan.INSTANCE.getPlugin().saveConfig(); + Vulcan.INSTANCE.getPlugin().reloadConfig(); + } + + private Config() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + + static { + CHECK_DATA = new HashMap(); + ENABLED_CHECKS = new HashMap(); + MAX_VIOLATIONS = new HashMap(); + ALERT_INTERVAL = new HashMap(); + MINIMUM_VL_TO_NOTIFY = new HashMap(); + PUNISHMENT_COMMANDS = new HashMap>(); + PUNISHABLE = new HashMap(); + BROADCAST_PUNISHMENT = new HashMap(); + MAXIMUM_PING = new HashMap(); + MINIMUM_TPS = new HashMap(); + SETBACKS = new HashMap(); + MAX_BUFFERS = new HashMap(); + BUFFER_DECAYS = new HashMap(); + BUFFER_MULTIPLES = new HashMap(); + HOTBAR_SHUFFLE = new HashMap(); + HOTBAR_SHUFFLE_MINIMUM = new HashMap(); + HOTBAR_SHUFFLE_EVERY = new HashMap(); + RANDOM_ROTATION = new HashMap(); + RANDOM_ROTATION_MINIMUM = new HashMap(); + RANDOM_ROTATION_EVERY = new HashMap(); + DISCORD_ALERT_INTERVAL = new HashMap(); + MINIMUM_VIOLATIONS_TO_SETBACK = new HashMap(); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/config/Stats.java b/src/main/java/me/frep/vulcan/spigot/config/Stats.java new file mode 100644 index 0000000..32edfee --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/config/Stats.java @@ -0,0 +1,95 @@ +package me.frep.vulcan.spigot.config; + +import java.io.OutputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.util.logging.Level; +import java.util.Date; +import me.frep.vulcan.spigot.Vulcan; +import java.io.File; +import me.frep.vulcan.spigot.config.type.CommentedConfiguration; + +public final class Stats +{ + private static final String fileName = "stats"; + private static CommentedConfiguration config; + private static File file; + + public static void save() { + try { + Stats.config.save(Stats.file); + } + catch (final Exception exception) { + final File newFile = new File(Vulcan.INSTANCE.getPlugin().getDataFolder(), "stats.broken." + new Date().getTime()); + Vulcan.INSTANCE.getPlugin().getLogger().log(Level.SEVERE, "Could not save: stats.yml"); + Vulcan.INSTANCE.getPlugin().getLogger().log(Level.SEVERE, "Regenerating file and renaming the current file to: " + newFile.getName()); + Vulcan.INSTANCE.getPlugin().getLogger().log(Level.SEVERE, "You can try fixing the file with a yaml parser online!"); + Stats.file.renameTo(newFile); + initialize(); + } + } + + public static void reload() { + try { + Stats.config.load(Stats.file); + } + catch (final Exception exception) { + final File newFile = new File(Vulcan.INSTANCE.getPlugin().getDataFolder(), "stats.broken." + new Date().getTime()); + Vulcan.INSTANCE.getPlugin().getLogger().log(Level.SEVERE, "Could not save: stats.yml"); + Vulcan.INSTANCE.getPlugin().getLogger().log(Level.SEVERE, "Regenerating file and renaming the current file to: " + newFile.getName()); + Vulcan.INSTANCE.getPlugin().getLogger().log(Level.SEVERE, "You can try fixing the file with a yaml parser online!"); + Stats.file.renameTo(newFile); + initialize(); + } + } + + public static void initialize() { + if (!Vulcan.INSTANCE.getPlugin().getDataFolder().exists()) { + Vulcan.INSTANCE.getPlugin().getDataFolder().mkdir(); + } + Stats.file = new File(Vulcan.INSTANCE.getPlugin().getDataFolder(), "stats.yml"); + if (!Stats.file.exists()) { + Stats.file.getParentFile().mkdirs(); + copy(Vulcan.INSTANCE.getPlugin().getResource("stats.yml"), Stats.file); + } + Stats.config = CommentedConfiguration.loadConfiguration(Stats.file); + try { + Stats.config.syncWithConfig(Stats.file, Vulcan.INSTANCE.getPlugin().getResource("stats.yml"), "NONE"); + } + catch (final Exception ex) {} + } + + private static void copy(final InputStream in, final File file) { + try { + final OutputStream out = new FileOutputStream(file); + final byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + out.close(); + in.close(); + } + catch (final Exception exception) { + exception.printStackTrace(); + } + } + + public static int getInt(final String path) { + return Stats.config.getInt(path); + } + + public static int getPunishments() { + return getInt("punishments"); + } + + public static void set(final String path, final Object object) { + Stats.config.set(path, object); + save(); + reload(); + } + + private Stats() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/config/type/CommentedConfiguration.java b/src/main/java/me/frep/vulcan/spigot/config/type/CommentedConfiguration.java new file mode 100644 index 0000000..01e6398 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/config/type/CommentedConfiguration.java @@ -0,0 +1,266 @@ +package me.frep.vulcan.spigot.config.type; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import org.bukkit.Bukkit; +import java.io.Reader; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.io.FileInputStream; +import java.util.stream.Stream; +import java.util.function.Predicate; +import java.util.Objects; +import org.bukkit.configuration.ConfigurationSection; +import java.util.Iterator; +import java.util.List; +import java.util.Collection; +import java.util.ArrayList; +import org.bukkit.configuration.InvalidConfigurationException; +import java.io.IOException; +import java.util.Arrays; +import java.io.InputStream; +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import org.bukkit.configuration.file.YamlConfiguration; + +public final class CommentedConfiguration extends YamlConfiguration +{ + private final Map configComments; + private boolean creationFailure; + + public CommentedConfiguration() { + this.configComments = new HashMap(); + this.creationFailure = false; + } + + public void syncWithConfig(final File file, final InputStream resource, final String... ignoredSections) throws IOException { + if (this.creationFailure) { + return; + } + final CommentedConfiguration cfg = loadConfiguration(resource); + if (this.syncConfigurationSection(cfg, cfg.getConfigurationSection(""), Arrays.asList(ignoredSections)) && file != null) { + this.save(file); + } + } + + public void setComment(final String path, final String comment) { + if (comment == null) { + this.configComments.remove(path); + } + else { + this.configComments.put(path, comment); + } + } + + public String getComment(final String path) { + return this.getComment(path, null); + } + + public String getComment(final String path, final String def) { + return this.configComments.getOrDefault(path, def); + } + + public boolean containsComment(final String path) { + return this.getComment(path) != null; + } + + public boolean hasFailed() { + return this.creationFailure; + } + + @Override + public void loadFromString(final String contents) throws InvalidConfigurationException { + super.loadFromString(contents); + final String[] lines = contents.split("\n"); + int currentIndex = 0; + StringBuilder comments = new StringBuilder(); + String currentSection = ""; + while (currentIndex < lines.length) { + if (isComment(lines[currentIndex])) { + comments.append(lines[currentIndex]).append("\n"); + } + else if (isNewSection(lines[currentIndex])) { + currentSection = getSectionPath(this, lines[currentIndex], currentSection); + if (comments.length() > 1) { + this.setComment(currentSection, comments.toString().substring(0, comments.length() - 1)); + } + comments = new StringBuilder(); + } + ++currentIndex; + } + } + + @Override + public String saveToString() { + this.options().header(null); + final List lines = new ArrayList(Arrays.asList(super.saveToString().split("\n"))); + int currentIndex = 0; + String currentSection = ""; + while (currentIndex < lines.size()) { + final String line = lines.get(currentIndex); + if (isNewSection(line)) { + currentSection = getSectionPath(this, line, currentSection); + if (this.containsComment(currentSection)) { + lines.add(currentIndex, this.getComment(currentSection)); + ++currentIndex; + } + } + ++currentIndex; + } + final StringBuilder contents = new StringBuilder(); + for (final String line2 : lines) { + contents.append("\n").append(line2); + } + return (contents.length() == 0) ? "" : contents.substring(1); + } + + private boolean syncConfigurationSection(final CommentedConfiguration commentedConfig, final ConfigurationSection section, final List ignoredSections) { + boolean changed = false; + for (final String key : section.getKeys(false)) { + final String path = section.getCurrentPath().isEmpty() ? key : (section.getCurrentPath() + "." + key); + if (section.isConfigurationSection(key)) { + final Stream stream = ignoredSections.stream(); + final String obj = path; + Objects.requireNonNull(obj); + final boolean isIgnored = stream.anyMatch(obj::contains); + final boolean containsSection = this.contains(path); + if (!containsSection || !isIgnored) { + changed = (this.syncConfigurationSection(commentedConfig, section.getConfigurationSection(key), ignoredSections) || changed); + } + } + else if (!this.contains(path)) { + this.set(path, section.get(key)); + changed = true; + } + if (commentedConfig.containsComment(path) && !commentedConfig.getComment(path).equals(this.getComment(path))) { + this.setComment(path, commentedConfig.getComment(path)); + changed = true; + } + } + if (changed) { + correctIndexes(section, this.getConfigurationSection(section.getCurrentPath())); + } + return changed; + } + + private CommentedConfiguration flagAsFailed() { + this.creationFailure = true; + return this; + } + + public static CommentedConfiguration loadConfiguration(final File file) { + try { + final FileInputStream stream = new FileInputStream(file); + return loadConfiguration(new InputStreamReader(stream, StandardCharsets.UTF_8)); + } + catch (final FileNotFoundException ex) { + Bukkit.getLogger().warning("File " + file.getName() + " doesn't exist."); + return new CommentedConfiguration().flagAsFailed(); + } + } + + public static CommentedConfiguration loadConfiguration(final InputStream inputStream) { + return loadConfiguration(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); + } + + public static CommentedConfiguration loadConfiguration(final Reader reader) { + final CommentedConfiguration config = new CommentedConfiguration(); + try (final BufferedReader bufferedReader = (BufferedReader)((reader instanceof BufferedReader) ? reader : new BufferedReader(reader))) { + final StringBuilder contents = new StringBuilder(); + String line; + while ((line = bufferedReader.readLine()) != null) { + contents.append(line).append('\n'); + } + config.loadFromString(contents.toString()); + } + catch (final IOException | InvalidConfigurationException ex) { + config.flagAsFailed(); + ex.printStackTrace(); + } + return config; + } + + private static boolean isNewSection(final String line) { + final String trimLine = line.trim(); + return trimLine.contains(": ") || trimLine.endsWith(":"); + } + + private static String getSectionPath(final CommentedConfiguration commentedConfig, final String line, final String currentSection) { + String newSection = line.trim().split(": ")[0]; + if (newSection.endsWith(":")) { + newSection = newSection.substring(0, newSection.length() - 1); + } + if (newSection.startsWith(".")) { + newSection = newSection.substring(1); + } + if (newSection.startsWith("'") && newSection.endsWith("'")) { + newSection = newSection.substring(1, newSection.length() - 1); + } + if (!currentSection.isEmpty() && commentedConfig.contains(currentSection + "." + newSection)) { + newSection = currentSection + "." + newSection; + } + else { + String parentSection = currentSection; + while (!parentSection.isEmpty() && !commentedConfig.contains((parentSection = getParentPath(parentSection)) + "." + newSection)) {} + newSection = (parentSection.trim().isEmpty() ? newSection : (parentSection + "." + newSection)); + } + return newSection; + } + + private static boolean isComment(final String line) { + final String trimLine = line.trim(); + return trimLine.startsWith("CRAFTBUKKIT_ARE_FUCKING_IDIOTS"); + } + + private static String getParentPath(final String path) { + return path.contains(".") ? path.substring(0, path.lastIndexOf(46)) : ""; + } + + private static void correctIndexes(final ConfigurationSection section, final ConfigurationSection target) { + final List> sectionMap = getSectionMap(section); + final List> correctOrder = new ArrayList>(); + for (final Pair entry : sectionMap) { + correctOrder.add(new Pair<>((entry).key, target.get(entry.key))); + } + clearConfiguration(target); + for (final Pair entry : correctOrder) { + target.set(entry.key, entry.value); + } + } + + private static List> getSectionMap(final ConfigurationSection section) { + final List> list = new ArrayList>(); + for (final String key : section.getKeys(false)) { + list.add(new Pair(key, section.get(key))); + } + return list; + } + + private static void clearConfiguration(final ConfigurationSection section) { + for (final String key : section.getKeys(false)) { + section.set(key, null); + } + } + + private static class Pair + { + private final K key; + private final V value; + + Pair(final K key, final V value) { + this.key = key; + this.value = value; + } + + @Override + public boolean equals(final Object obj) { + return obj instanceof Pair && this.key.equals(((Pair)obj).key) && this.value.equals(((Pair)obj).value); + } + + @Override + public int hashCode() { + return this.key.hashCode(); + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/config/updater/ConfigUpdater.java b/src/main/java/me/frep/vulcan/spigot/config/updater/ConfigUpdater.java new file mode 100644 index 0000000..7fd9154 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/config/updater/ConfigUpdater.java @@ -0,0 +1,281 @@ +package me.frep.vulcan.spigot.config.updater; + +import java.util.Set; +import java.util.HashMap; +import org.bukkit.configuration.serialization.ConfigurationSerializable; +import java.util.Iterator; +import org.bukkit.configuration.ConfigurationSection; +import java.io.IOException; +import java.util.Map; +import org.bukkit.configuration.file.FileConfiguration; +import org.yaml.snakeyaml.Yaml; +import java.util.Collection; +import java.util.ArrayList; +import java.io.Writer; +import java.io.BufferedWriter; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.FileOutputStream; +import org.bukkit.configuration.file.YamlConfiguration; +import java.util.stream.Collector; +import java.util.stream.Collectors; +import java.io.Reader; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.io.File; +import org.bukkit.plugin.Plugin; + +public final class ConfigUpdater +{ + public static void update(final Plugin plugin, final String resourceName, final File toUpdate, final List ignoredSections) throws IOException { + final BufferedReader newReader = new BufferedReader(new InputStreamReader(plugin.getResource(resourceName), StandardCharsets.UTF_8)); + final List newLines = newReader.lines().collect(Collectors.toList()); + newReader.close(); + final FileConfiguration oldConfig = YamlConfiguration.loadConfiguration(toUpdate); + final FileConfiguration newConfig = YamlConfiguration.loadConfiguration(new InputStreamReader(plugin.getResource(resourceName), StandardCharsets.UTF_8)); + final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(toUpdate), StandardCharsets.UTF_8)); + final List ignoredSectionsArrayList = new ArrayList(ignoredSections); + ignoredSectionsArrayList.removeIf(ignoredSection -> !newConfig.isConfigurationSection(ignoredSection)); + final Yaml yaml = new Yaml(); + final Map comments = parseComments(newLines, ignoredSectionsArrayList, oldConfig, yaml); + write(newConfig, oldConfig, comments, ignoredSectionsArrayList, writer, yaml); + } + + private static void write(final FileConfiguration newConfig, final FileConfiguration oldConfig, final Map comments, final List ignoredSections, final BufferedWriter writer, final Yaml yaml) throws IOException { + Label_0012: + for (final String key : newConfig.getKeys(true)) { + final String[] keys = key.split("\\."); + final String actualKey = keys[keys.length - 1]; + final String comment = comments.remove(key); + final StringBuilder prefixBuilder = new StringBuilder(); + final int indents = keys.length - 1; + appendPrefixSpaces(prefixBuilder, indents); + final String prefixSpaces = prefixBuilder.toString(); + if (comment != null) { + writer.write(comment); + } + for (final String ignoredSection : ignoredSections) { + if (key.startsWith(ignoredSection)) { + continue Label_0012; + } + } + final Object newObj = newConfig.get(key); + final Object oldObj = oldConfig.get(key); + if (newObj instanceof ConfigurationSection && oldObj instanceof ConfigurationSection) { + writeSection(writer, actualKey, prefixSpaces, (ConfigurationSection)oldObj); + } + else if (newObj instanceof ConfigurationSection) { + writeSection(writer, actualKey, prefixSpaces, (ConfigurationSection)newObj); + } + else if (oldObj != null) { + write(oldObj, actualKey, prefixSpaces, yaml, writer); + } + else { + write(newObj, actualKey, prefixSpaces, yaml, writer); + } + } + final String danglingComments = comments.get(null); + if (danglingComments != null) { + writer.write(danglingComments); + } + writer.close(); + } + + private static void write(Object obj, final String actualKey, final String prefixSpaces, final Yaml yaml, final BufferedWriter writer) throws IOException { + if (obj instanceof ConfigurationSerializable) { + writer.write(prefixSpaces + actualKey + ": " + yaml.dump(((ConfigurationSerializable)obj).serialize())); + } + else if (obj instanceof String || obj instanceof Character) { + if (obj instanceof String) { + final String s = (String)obj; + obj = s.replace("\n", "\\n"); + } + writer.write(prefixSpaces + actualKey + ": " + yaml.dump(obj)); + } + else if (obj instanceof List) { + writeList((List)obj, actualKey, prefixSpaces, yaml, writer); + } + else { + writer.write(prefixSpaces + actualKey + ": " + yaml.dump(obj)); + } + } + + private static void writeSection(final BufferedWriter writer, final String actualKey, final String prefixSpaces, final ConfigurationSection section) throws IOException { + if (section.getKeys(false).isEmpty()) { + writer.write(prefixSpaces + actualKey + ": {}"); + } + else { + writer.write(prefixSpaces + actualKey + ":"); + } + writer.write("\n"); + } + + private static void writeList(final List list, final String actualKey, final String prefixSpaces, final Yaml yaml, final BufferedWriter writer) throws IOException { + writer.write(getListAsString(list, actualKey, prefixSpaces, yaml)); + } + + private static String getListAsString(final List list, final String actualKey, final String prefixSpaces, final Yaml yaml) { + final StringBuilder builder = new StringBuilder(prefixSpaces).append(actualKey).append(":"); + if (list.isEmpty()) { + builder.append(" []\n"); + return builder.toString(); + } + builder.append("\n"); + for (int i = 0; i < list.size(); ++i) { + final Object o = list.get(i); + if (o instanceof String) { + final String s = String.valueOf(o); + builder.append(prefixSpaces).append(" - \"").append(s).append("\""); + } + else if (o instanceof Character) { + builder.append(prefixSpaces).append(" - '").append(o).append("'"); + } + else if (o instanceof List) { + builder.append(prefixSpaces).append(" - ").append(yaml.dump(o)); + } + else { + builder.append(prefixSpaces).append(" - ").append(o); + } + if (i != list.size()) { + builder.append("\n"); + } + } + return builder.toString(); + } + + private static Map parseComments(final List lines, final List ignoredSections, final FileConfiguration oldConfig, final Yaml yaml) { + final Map comments = new HashMap(); + final StringBuilder builder = new StringBuilder(); + final StringBuilder keyBuilder = new StringBuilder(); + int lastLineIndentCount = 0; + Label_0038: + for (final String line : lines) { + if (line != null && line.trim().startsWith("-")) { + continue; + } + if (line == null || line.trim().equals("") || line.trim().startsWith("#")) { + builder.append(line).append("\n"); + } + else { + lastLineIndentCount = setFullKey(keyBuilder, line, lastLineIndentCount); + for (final String ignoredSection : ignoredSections) { + if (keyBuilder.toString().equals(ignoredSection)) { + final Object value = oldConfig.get(keyBuilder.toString()); + if (value instanceof ConfigurationSection) { + appendSection(builder, (ConfigurationSection)value, new StringBuilder(getPrefixSpaces(lastLineIndentCount)), yaml); + continue Label_0038; + } + continue Label_0038; + } + } + if (keyBuilder.length() <= 0) { + continue; + } + comments.put(keyBuilder.toString(), builder.toString()); + builder.setLength(0); + } + } + if (builder.length() > 0) { + comments.put(null, builder.toString()); + } + return comments; + } + + private static void appendSection(final StringBuilder builder, final ConfigurationSection section, final StringBuilder prefixSpaces, final Yaml yaml) { + builder.append((CharSequence)prefixSpaces).append(getKeyFromFullKey(section.getCurrentPath())).append(":"); + final Set keys = section.getKeys(false); + if (keys.isEmpty()) { + builder.append(" {}\n"); + return; + } + builder.append("\n"); + prefixSpaces.append(" "); + for (final String key : keys) { + final Object value = section.get(key); + final String actualKey = getKeyFromFullKey(key); + if (value instanceof ConfigurationSection) { + appendSection(builder, (ConfigurationSection)value, prefixSpaces, yaml); + prefixSpaces.setLength(prefixSpaces.length() - 2); + } + else if (value instanceof List) { + builder.append(getListAsString((List)value, actualKey, prefixSpaces.toString(), yaml)); + } + else { + builder.append(prefixSpaces.toString()).append(actualKey).append(": ").append(yaml.dump(value)); + } + } + } + + private static int countIndents(final String s) { + int spaces = 0; + for (final char c : s.toCharArray()) { + if (c != ' ') { + break; + } + ++spaces; + } + return spaces / 2; + } + + private static void removeLastKey(final StringBuilder keyBuilder) { + String temp = keyBuilder.toString(); + final String[] keys = temp.split("\\."); + if (keys.length == 1) { + keyBuilder.setLength(0); + return; + } + temp = temp.substring(0, temp.length() - keys[keys.length - 1].length() - 1); + keyBuilder.setLength(temp.length()); + } + + private static String getKeyFromFullKey(final String fullKey) { + final String[] keys = fullKey.split("\\."); + return keys[keys.length - 1]; + } + + private static int setFullKey(final StringBuilder keyBuilder, final String configLine, final int lastLineIndentCount) { + final int currentIndents = countIndents(configLine); + final String key = configLine.trim().split(":")[0]; + if (keyBuilder.length() == 0) { + keyBuilder.append(key); + } + else if (currentIndents == lastLineIndentCount) { + removeLastKey(keyBuilder); + if (keyBuilder.length() > 0) { + keyBuilder.append("."); + } + keyBuilder.append(key); + } + else if (currentIndents > lastLineIndentCount) { + keyBuilder.append(".").append(key); + } + else { + for (int difference = lastLineIndentCount - currentIndents, i = 0; i < difference + 1; ++i) { + removeLastKey(keyBuilder); + } + if (keyBuilder.length() > 0) { + keyBuilder.append("."); + } + keyBuilder.append(key); + } + return currentIndents; + } + + private static String getPrefixSpaces(final int indents) { + final StringBuilder builder = new StringBuilder(); + for (int i = 0; i < indents; ++i) { + builder.append(" "); + } + return builder.toString(); + } + + private static void appendPrefixSpaces(final StringBuilder builder, final int indents) { + builder.append(getPrefixSpaces(indents)); + } + + private ConfigUpdater() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/data/PlayerData.java b/src/main/java/me/frep/vulcan/spigot/data/PlayerData.java new file mode 100644 index 0000000..41796fc --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/data/PlayerData.java @@ -0,0 +1,311 @@ +package me.frep.vulcan.spigot.data; + +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import java.util.ArrayList; +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.check.manager.CheckManager; +import me.frep.vulcan.spigot.Vulcan; +import me.frep.vulcan.spigot.data.processor.ConnectionProcessor; +import me.frep.vulcan.spigot.data.processor.VelocityProcessor; +import me.frep.vulcan.spigot.data.processor.RotationProcessor; +import me.frep.vulcan.spigot.data.processor.PositionProcessor; +import me.frep.vulcan.spigot.data.processor.ClickProcessor; +import me.frep.vulcan.spigot.data.processor.ActionProcessor; +import me.frep.vulcan.spigot.data.processor.CombatProcessor; +import me.frep.vulcan.spigot.exempt.ExemptProcessor; +import me.frep.vulcan.spigot.check.AbstractCheck; +import java.util.List; +import io.github.retrooper.packetevents.packetwrappers.play.in.helditemslot.WrappedPacketInHeldItemSlot; +import io.github.retrooper.packetevents.packetwrappers.play.in.entityaction.WrappedPacketInEntityAction; +import io.github.retrooper.packetevents.packetwrappers.play.in.blockdig.WrappedPacketInBlockDig; +import io.github.retrooper.packetevents.packetwrappers.play.in.useentity.WrappedPacketInUseEntity; +import io.github.retrooper.packetevents.packetwrappers.play.in.flying.WrappedPacketInFlying; +import io.github.retrooper.packetevents.utils.player.ClientVersion; +import org.bukkit.entity.Player; +import me.frep.vulcan.api.data.IPlayerData; + +public class PlayerData implements IPlayerData +{ + private final Player player; + private ClientVersion clientVersion; + private String clientBrand; + private boolean hasSentClientBrand; + private int totalViolations; + private int combatViolations; + private int movementViolations; + private int playerViolations; + private int autoClickerViolations; + private int scaffoldViolations; + private int timerViolations; + private final long joinTime; + private final int joinTicks; + private long lastClientBrandAlert; + private long lastPunishment; + private WrappedPacketInFlying flyingWrapper; + private WrappedPacketInUseEntity useEntityWrapper; + private WrappedPacketInBlockDig blockDigWrapper; + private WrappedPacketInEntityAction entityActionWrapper; + private WrappedPacketInHeldItemSlot heldItemSlotWrapper; + private int pendingTransactions; + private final List checks; + private final ExemptProcessor exemptProcessor; + private final CombatProcessor combatProcessor; + private final ActionProcessor actionProcessor; + private final ClickProcessor clickProcessor; + private final PositionProcessor positionProcessor; + private final RotationProcessor rotationProcessor; + private final VelocityProcessor velocityProcessor; + private final ConnectionProcessor connectionProcessor; + + public PlayerData(final Player player) { + this.clientVersion = ClientVersion.UNRESOLVED; + this.clientBrand = "Unresolved"; + this.hasSentClientBrand = false; + this.joinTime = System.currentTimeMillis(); + this.joinTicks = Vulcan.INSTANCE.getTickManager().getTicks(); + this.pendingTransactions = 0; + this.checks = CheckManager.loadChecks(this); + this.exemptProcessor = new ExemptProcessor(this); + this.combatProcessor = new CombatProcessor(this); + this.actionProcessor = new ActionProcessor(this); + this.clickProcessor = new ClickProcessor(this); + this.positionProcessor = new PositionProcessor(this); + this.rotationProcessor = new RotationProcessor(this); + this.velocityProcessor = new VelocityProcessor(this); + this.connectionProcessor = new ConnectionProcessor(this); + this.player = player; + } + + public void sendTransaction(final short id) { + PlayerUtil.sendTransaction(this.player, id); + } + + public void sendPing(final int id) { + PlayerUtil.sendPing(this.player, id); + } + + public boolean is1_17() { + return PlayerUtil.is1_17(this); + } + + public boolean is1_13() { + return PlayerUtil.is1_13(this); + } + + public boolean is1_9() { + return PlayerUtil.is1_9(this); + } + + public List getExemptions() { + final List exempts = new ArrayList(); + for (final ExemptType exemptType : ExemptType.values()) { + if (this.exemptProcessor.isExempt(exemptType)) { + exempts.add(exemptType.toString()); + } + } + return exempts; + } + + public Player getPlayer() { + return this.player; + } + + public ClientVersion getClientVersion() { + return this.clientVersion; + } + + @Override + public String getClientBrand() { + return this.clientBrand; + } + + public boolean isHasSentClientBrand() { + return this.hasSentClientBrand; + } + + @Override + public int getTotalViolations() { + return this.totalViolations; + } + + @Override + public int getCombatViolations() { + return this.combatViolations; + } + + @Override + public int getMovementViolations() { + return this.movementViolations; + } + + @Override + public int getPlayerViolations() { + return this.playerViolations; + } + + @Override + public int getAutoClickerViolations() { + return this.autoClickerViolations; + } + + @Override + public int getScaffoldViolations() { + return this.scaffoldViolations; + } + + @Override + public int getTimerViolations() { + return this.timerViolations; + } + + @Override + public long getJoinTime() { + return this.joinTime; + } + + @Override + public int getJoinTicks() { + return this.joinTicks; + } + + @Override + public long getLastClientBrandAlert() { + return this.lastClientBrandAlert; + } + + public long getLastPunishment() { + return this.lastPunishment; + } + + public WrappedPacketInFlying getFlyingWrapper() { + return this.flyingWrapper; + } + + public WrappedPacketInUseEntity getUseEntityWrapper() { + return this.useEntityWrapper; + } + + public WrappedPacketInBlockDig getBlockDigWrapper() { + return this.blockDigWrapper; + } + + public WrappedPacketInEntityAction getEntityActionWrapper() { + return this.entityActionWrapper; + } + + public WrappedPacketInHeldItemSlot getHeldItemSlotWrapper() { + return this.heldItemSlotWrapper; + } + + public int getPendingTransactions() { + return this.pendingTransactions; + } + + public List getChecks() { + return this.checks; + } + + public ExemptProcessor getExemptProcessor() { + return this.exemptProcessor; + } + + public CombatProcessor getCombatProcessor() { + return this.combatProcessor; + } + + public ActionProcessor getActionProcessor() { + return this.actionProcessor; + } + + public ClickProcessor getClickProcessor() { + return this.clickProcessor; + } + + public PositionProcessor getPositionProcessor() { + return this.positionProcessor; + } + + public RotationProcessor getRotationProcessor() { + return this.rotationProcessor; + } + + public VelocityProcessor getVelocityProcessor() { + return this.velocityProcessor; + } + + public ConnectionProcessor getConnectionProcessor() { + return this.connectionProcessor; + } + + public void setClientVersion(final ClientVersion clientVersion) { + this.clientVersion = clientVersion; + } + + public void setClientBrand(final String clientBrand) { + this.clientBrand = clientBrand; + } + + public void setHasSentClientBrand(final boolean hasSentClientBrand) { + this.hasSentClientBrand = hasSentClientBrand; + } + + public void setTotalViolations(final int totalViolations) { + this.totalViolations = totalViolations; + } + + public void setCombatViolations(final int combatViolations) { + this.combatViolations = combatViolations; + } + + public void setMovementViolations(final int movementViolations) { + this.movementViolations = movementViolations; + } + + public void setPlayerViolations(final int playerViolations) { + this.playerViolations = playerViolations; + } + + public void setAutoClickerViolations(final int autoClickerViolations) { + this.autoClickerViolations = autoClickerViolations; + } + + public void setScaffoldViolations(final int scaffoldViolations) { + this.scaffoldViolations = scaffoldViolations; + } + + public void setTimerViolations(final int timerViolations) { + this.timerViolations = timerViolations; + } + + public void setLastClientBrandAlert(final long lastClientBrandAlert) { + this.lastClientBrandAlert = lastClientBrandAlert; + } + + public void setLastPunishment(final long lastPunishment) { + this.lastPunishment = lastPunishment; + } + + public void setFlyingWrapper(final WrappedPacketInFlying flyingWrapper) { + this.flyingWrapper = flyingWrapper; + } + + public void setUseEntityWrapper(final WrappedPacketInUseEntity useEntityWrapper) { + this.useEntityWrapper = useEntityWrapper; + } + + public void setBlockDigWrapper(final WrappedPacketInBlockDig blockDigWrapper) { + this.blockDigWrapper = blockDigWrapper; + } + + public void setEntityActionWrapper(final WrappedPacketInEntityAction entityActionWrapper) { + this.entityActionWrapper = entityActionWrapper; + } + + public void setHeldItemSlotWrapper(final WrappedPacketInHeldItemSlot heldItemSlotWrapper) { + this.heldItemSlotWrapper = heldItemSlotWrapper; + } + + public void setPendingTransactions(final int pendingTransactions) { + this.pendingTransactions = pendingTransactions; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/data/manager/PlayerDataManager.java b/src/main/java/me/frep/vulcan/spigot/data/manager/PlayerDataManager.java new file mode 100644 index 0000000..614c5ab --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/data/manager/PlayerDataManager.java @@ -0,0 +1,34 @@ +package me.frep.vulcan.spigot.data.manager; + +import java.util.Collection; +import org.bukkit.entity.Player; +import com.google.common.collect.Maps; +import me.frep.vulcan.spigot.data.PlayerData; +import java.util.UUID; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public final class PlayerDataManager +{ + private final Map playerDataMap; + + public PlayerDataManager() { + this.playerDataMap = new ConcurrentHashMap<>(); + } + + public PlayerData getPlayerData(final Player player) { + return this.playerDataMap.get(player.getUniqueId()); + } + + public void add(final Player player) { + this.playerDataMap.put(player.getUniqueId(), new PlayerData(player)); + } + + public void remove(final Player player) { + this.playerDataMap.remove(player.getUniqueId()); + } + + public Collection getAllData() { + return this.playerDataMap.values(); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/data/processor/ActionProcessor.java b/src/main/java/me/frep/vulcan/spigot/data/processor/ActionProcessor.java new file mode 100644 index 0000000..9202057 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/data/processor/ActionProcessor.java @@ -0,0 +1,2272 @@ +package me.frep.vulcan.spigot.data.processor; + +import org.bukkit.potion.PotionEffectType; +import io.github.retrooper.packetevents.utils.vector.Vector3f; +import io.github.retrooper.packetevents.packetwrappers.play.out.explosion.WrappedPacketOutExplosion; +import io.github.retrooper.packetevents.packetwrappers.play.out.entitymetadata.WrappedWatchableObject; +import io.github.retrooper.packetevents.packetwrappers.play.out.entitymetadata.WrappedPacketOutEntityMetadata; +import org.bukkit.event.block.BlockPlaceEvent; +import io.github.retrooper.packetevents.packetwrappers.play.out.abilities.WrappedPacketOutAbilities; +import me.frep.vulcan.spigot.util.PlayerUtil; +import org.bukkit.enchantments.Enchantment; +import io.github.retrooper.packetevents.packetwrappers.play.in.flying.WrappedPacketInFlying; +import org.bukkit.event.entity.EntityDamageEvent; +import io.github.retrooper.packetevents.packetwrappers.play.in.pong.WrappedPacketInPong; +import io.github.retrooper.packetevents.utils.vector.Vector3d; +import io.github.retrooper.packetevents.packetwrappers.play.in.transaction.WrappedPacketInTransaction; +import me.frep.vulcan.spigot.util.MathUtil; +import io.github.retrooper.packetevents.packetwrappers.play.in.clientcommand.WrappedPacketInClientCommand; +import me.frep.vulcan.spigot.util.ServerUtil; +import org.bukkit.entity.EntityType; +import io.github.retrooper.packetevents.packetwrappers.play.in.blockdig.WrappedPacketInBlockDig; +import me.frep.vulcan.spigot.Vulcan; +import io.github.retrooper.packetevents.packetwrappers.play.in.entityaction.WrappedPacketInEntityAction; +import java.util.Iterator; +import java.util.List; +import io.github.retrooper.packetevents.utils.attributesnapshot.AttributeSnapshotWrapper; +import io.github.retrooper.packetevents.packetwrappers.play.out.updateattributes.WrappedPacketOutUpdateAttributes; +import java.util.HashMap; +import org.bukkit.util.Vector; +import me.frep.vulcan.spigot.util.type.EvictingList; +import org.bukkit.inventory.ItemStack; +import io.github.retrooper.packetevents.packetwrappers.play.out.position.WrappedPacketOutPosition; +import io.github.retrooper.packetevents.packetwrappers.play.out.gamestatechange.WrappedPacketOutGameStateChange; +import io.github.retrooper.packetevents.packetwrappers.play.out.removeentityeffect.WrappedPacketOutRemoveEntityEffect; +import io.github.retrooper.packetevents.packetwrappers.play.out.entityeffect.WrappedPacketOutEntityEffect; +import java.util.Map; +import org.bukkit.GameMode; +import me.frep.vulcan.spigot.data.PlayerData; + +public class ActionProcessor +{ + private final PlayerData data; + private boolean sprinting; + private boolean sneaking; + private boolean sendingAction; + private boolean placing; + private boolean digging; + private boolean blocking; + private boolean inventory; + private boolean sendingDig; + private boolean teleporting; + private boolean hasSpeed; + private boolean hasJumpBoost; + private boolean hasLevitation; + private boolean hasSlowFalling; + private boolean hasDolphinsGrace; + private boolean sitting; + private boolean hasConduitsPower; + private boolean crawling; + private boolean hasSlowness; + private boolean wearingDepthStrider; + private boolean wearingElytra; + private boolean bukkitGliding; + private boolean packetGliding; + private boolean packetSwimming; + private boolean updateSwim; + private double genericMovementSpeed; + private boolean berserking; + private int lastBukkitDiggingTick; + private int lastDropItemTick; + private int lastDiggingTick; + private int sinceSprintingTicks; + private int positionTicksExisted; + private int lastWindowClick; + private int amount; + private int lastAmount; + private int slot; + private int lastSlot; + private int sinceTeleportTicks; + private int sinceExplosionTicks; + private int lastBedEnter; + private int lastBedLeave; + private int lastItemPickup; + private int lastCancelledBreak; + private int lastChorusFruitTeleport; + private int lastDamage; + private int sinceDragonDamageTicks; + private int sprintingTicks; + private int lastRespawn; + private int lastLowHealth; + private int lastProjectileThrow; + private int lastFishEvent; + private int sinceFireDamageTicks; + private int sinceAttackDamageTicks; + private int sinceFallDamageTicks; + private int sinceMagicDamageTicks; + private int sincePoisonDamageTicks; + private int sinceContactDamageTicks; + private int sinceProjectileDamageTicks; + private int lastLavaDamage; + private int sinceLavaDamageTicks; + private int sinceExplosionDamageTicks; + private int sinceBucketEmptyTicks; + private int sinceBlockPlaceTicks; + private int sinceClimbablePlaceTicks; + private int sinceSlimePlaceTicks; + private int sinceCancelledPlaceTicks; + private int sinceWorldChangeTicks; + private int sinceRessurectTicks; + private int sinceBukkitTeleportTicks; + private int sinceDeathTicks; + private int sinceNonFallDamageTicks; + private int sinceIronGolemDamageTicks; + private int lastScaffoldPlaceX; + private int lastScaffoldPlaceY; + private int lastScaffoldPlaceZ; + private int sinceBerserkTicks; + private int sinceCrackshotDamageTicks; + private int sinceGlassBottleFillTicks; + private int sinceFireballDamageTicks; + private int speedAmplifier; + private int jumpBoostAmplifier; + private int levitationAmplifier; + private int slowFallingAmplifier; + private int dolphinsGraceAmplifier; + private int sinceChorusFruitTeleportTicks; + private int sinceWebPlaceTicks; + private int sinceEnderPearlTicks; + private int sinceBukkitVelocityTicks; + private int sinceDamageTicks; + private int sinceStartGlidingTicks; + private int sinceIcePlaceTicks; + private int sinceBlockBreakTicks; + private int ticksExisted; + private int sinceHoglinDamageTicks; + private int sinceAbilitiesTicks; + private int sincePushTicks; + private int sinceMythicMobTicks; + private int sinceCancelledMoveTicks; + private int sinceRavagerDamageTicks; + private int sinceWitherDamageTicks; + private int sinceCrystalDamageTicks; + private int sinceSuffociationDamageTicks; + private int sinceStupidBucketEmptyTicks; + private int sinceNetherrackBreakTicks; + private int sinceBowBoostTicks; + private double lastAbortX; + private double lastAbortZ; + private double distanceFromLastAbort; + private double lastBreakX; + private double lastBreakY; + private double lastBreakZ; + private double distanceFromLastBreak; + private double health; + private double distanceFromLastScaffoldPlace; + private double explosionX; + private double explosionY; + private double explosionZ; + private double lastTeleportX; + private double lastTeleportY; + private double lastTeleportZ; + private double distanceFromLastTeleport; + private double lastGlidingDeltaXZ; + private long lastStartDestroy; + private long lastStopDestroy; + private long lastAbort; + private GameMode gameMode; + private short positionTransactionId; + private short entityEffectTransactionId; + private short removeEntityEffectTransactionId; + private short gameStateChangeTransactionId; + private short positionPingId; + private short entityEffectPingId; + private short removeEntityEffectPingId; + private short gameStateChangePingId; + private final Map queuedEntityEffects; + private final Map queuedRemoveEntityEffects; + private final Map queuedGameStateChanges; + private final Map queuedTeleports; + private ItemStack helmet; + private ItemStack chestplate; + private ItemStack leggings; + private ItemStack boots; + private ItemStack itemInMainHand; + private ItemStack itemInOffHand; + private static final String GENERIC_MOVEMENT_SPEED; + final EvictingList teleports; + + public ActionProcessor(final PlayerData data) { + this.genericMovementSpeed = 0.0; + this.positionTicksExisted = 0; + this.sinceTeleportTicks = 100; + this.sinceExplosionTicks = 1000; + this.sinceDragonDamageTicks = 100; + this.sinceFireDamageTicks = 100; + this.sinceAttackDamageTicks = 100; + this.sinceFallDamageTicks = 100; + this.sinceExplosionDamageTicks = 100; + this.sinceBucketEmptyTicks = 100; + this.sinceBlockPlaceTicks = 100; + this.sinceClimbablePlaceTicks = 100; + this.sinceSlimePlaceTicks = 150; + this.sinceCancelledPlaceTicks = 100; + this.sinceWorldChangeTicks = 100; + this.sinceBukkitTeleportTicks = 100; + this.sinceDeathTicks = 100; + this.sinceNonFallDamageTicks = 100; + this.sinceGlassBottleFillTicks = 100; + this.sinceFireballDamageTicks = 100; + this.speedAmplifier = 0; + this.jumpBoostAmplifier = 0; + this.levitationAmplifier = 0; + this.slowFallingAmplifier = 0; + this.dolphinsGraceAmplifier = 0; + this.sinceChorusFruitTeleportTicks = 100; + this.sinceWebPlaceTicks = 100; + this.sinceEnderPearlTicks = 100; + this.sinceBukkitVelocityTicks = 100; + this.sinceDamageTicks = 100; + this.sinceStartGlidingTicks = 100; + this.sinceIcePlaceTicks = 100; + this.sinceBlockBreakTicks = 100; + this.ticksExisted = 0; + this.sinceAbilitiesTicks = 0; + this.sincePushTicks = 100; + this.sinceMythicMobTicks = 500; + this.sinceCancelledMoveTicks = 1000; + this.sinceRavagerDamageTicks = 1000; + this.sinceWitherDamageTicks = 100; + this.sinceCrystalDamageTicks = 100; + this.sinceSuffociationDamageTicks = 100; + this.sinceStupidBucketEmptyTicks = 100; + this.sinceNetherrackBreakTicks = 100; + this.sinceBowBoostTicks = 100; + this.gameMode = GameMode.SURVIVAL; + this.positionTransactionId = -29768; + this.entityEffectTransactionId = -28768; + this.removeEntityEffectTransactionId = -27768; + this.gameStateChangeTransactionId = -26768; + this.positionPingId = -29768; + this.entityEffectPingId = -28768; + this.removeEntityEffectPingId = -27768; + this.gameStateChangePingId = -26768; + this.queuedEntityEffects = new HashMap(); + this.queuedRemoveEntityEffects = new HashMap(); + this.queuedGameStateChanges = new HashMap(); + this.queuedTeleports = new HashMap(); + this.teleports = new EvictingList(15); + this.data = data; + } + + public void handleUpdateAttributes(final WrappedPacketOutUpdateAttributes wrapper) { + final List attributes = wrapper.getProperties(); + for (final AttributeSnapshotWrapper attribute : attributes) { + if (attribute.getKey().equals(ActionProcessor.GENERIC_MOVEMENT_SPEED)) { + this.genericMovementSpeed = attribute.getValue(); + } + } + } + + public void handleEntityAction(final WrappedPacketInEntityAction wrapper) { + this.sendingAction = true; + switch (wrapper.getAction()) { + case START_SPRINTING: { + this.sprinting = true; + break; + } + case STOP_SPRINTING: { + this.sprinting = false; + break; + } + case START_SNEAKING: { + this.sneaking = true; + break; + } + case STOP_SNEAKING: { + this.sneaking = false; + } + case START_FALL_FLYING: { + this.sinceStartGlidingTicks = 0; + break; + } + } + } + + public void handleItemPickup() { + this.lastItemPickup = Vulcan.INSTANCE.getTickManager().getTicks(); + } + + public void handleBukkitDig() { + this.lastBukkitDiggingTick = Vulcan.INSTANCE.getTickManager().getTicks(); + } + + public void handleBlockDig(final WrappedPacketInBlockDig wrapper) { + this.sendingDig = true; + switch (wrapper.getDigType()) { + case START_DESTROY_BLOCK: { + this.digging = true; + this.lastStartDestroy = System.currentTimeMillis(); + break; + } + case STOP_DESTROY_BLOCK: { + this.handleBlockBreak(wrapper.getBlockPosition().getX(), wrapper.getBlockPosition().getY(), wrapper.getBlockPosition().getZ()); + this.lastStopDestroy = System.currentTimeMillis(); + this.digging = false; + break; + } + case ABORT_DESTROY_BLOCK: { + this.lastAbort = System.currentTimeMillis(); + this.digging = false; + break; + } + case RELEASE_USE_ITEM: { + this.blocking = true; + break; + } + case DROP_ITEM: + case DROP_ALL_ITEMS: { + this.lastDropItemTick = Vulcan.INSTANCE.getTickManager().getTicks(); + break; + } + } + if (wrapper.getDigType() == WrappedPacketInBlockDig.PlayerDigType.ABORT_DESTROY_BLOCK) { + this.lastAbortX = wrapper.getBlockPosition().getX(); + this.lastAbortZ = wrapper.getBlockPosition().getZ(); + } + } + + public void handleBukkitAttackDamage(final EntityType entityType) { + switch (entityType) { + case ENDER_DRAGON: { + this.sinceDragonDamageTicks = 0; + break; + } + case IRON_GOLEM: { + this.sinceIronGolemDamageTicks = 0; + break; + } + case FIREBALL: + case SMALL_FIREBALL: + case DRAGON_FIREBALL: { + this.sinceFireballDamageTicks = 0; + break; + } + case WITHER: + case WITHER_SKULL: { + this.sinceWitherDamageTicks = 0; + break; + } + case ENDER_CRYSTAL: { + this.sinceCrystalDamageTicks = 0; + break; + } + } + if (ServerUtil.isHigherThan1_16() && entityType == EntityType.HOGLIN) { + this.sinceHoglinDamageTicks = 0; + } + if (ServerUtil.isHigherThan1_14() && entityType == EntityType.RAVAGER) { + this.sinceRavagerDamageTicks = 0; + } + } + + public void handleChorusTeleport() { + this.lastChorusFruitTeleport = Vulcan.INSTANCE.getTickManager().getTicks(); + this.sinceChorusFruitTeleportTicks = 0; + } + + public void handleCancelledBreak() { + this.lastCancelledBreak = Vulcan.INSTANCE.getTickManager().getTicks(); + } + + public void handleClientCommand(final WrappedPacketInClientCommand wrapper) { + switch (wrapper.getClientCommand()) { + case OPEN_INVENTORY_ACHIEVEMENT: { + this.inventory = true; + break; + } + case PERFORM_RESPAWN: { + this.lastRespawn = Vulcan.INSTANCE.getTickManager().getTicks(); + break; + } + } + } + + public void handleBlockPlace() { + this.placing = true; + if (ServerUtil.isHigherThan1_9() && (this.data.getPlayer().getInventory().getItemInMainHand().getType().toString().contains("FIREWORK") || this.data.getPlayer().getInventory().getItemInOffHand().getType().toString().contains("FIREWORK"))) { + this.data.getPositionProcessor().setSinceFireworkTicks(0); + } + } + + public void handleCloseWindow() { + this.inventory = false; + } + + public void handleWindowClick() { + this.lastWindowClick = Vulcan.INSTANCE.getTickManager().getTicks(); + } + + public void handleArmAnimation() { + if (this.digging) { + this.lastDiggingTick = Vulcan.INSTANCE.getTickManager().getTicks(); + } + else if (this.lastAbortX != 0.0 && this.lastAbortZ != 0.0) { + final double locationX = this.data.getPositionProcessor().getX(); + final double locationZ = this.data.getPositionProcessor().getZ(); + this.distanceFromLastAbort = MathUtil.hypot(Math.abs(locationX - this.lastAbortX), Math.abs(locationZ - this.lastAbortZ)); + if (this.distanceFromLastAbort > 12.0) { + final double lastAbortX = 0.0; + this.distanceFromLastAbort = lastAbortX; + this.lastAbortZ = lastAbortX; + this.lastAbortX = lastAbortX; + } + } + } + + public void handleBukkitPlace() { + this.sinceBlockPlaceTicks = 0; + this.handleCancelledBlockPlace(); + } + + private void handleCancelledBlockPlace() { + this.amount = this.data.getPlayer().getItemInHand().getAmount(); + this.slot = this.data.getPlayer().getInventory().getHeldItemSlot(); + if (this.amount == this.lastAmount && this.slot == this.lastSlot) { + this.sinceCancelledPlaceTicks = 0; + } + this.lastSlot = this.slot; + this.lastAmount = this.amount; + } + + public void handleBlockBreak(final double x, final double y, final double z) { + this.sinceBlockBreakTicks = 0; + this.lastBreakX = x; + this.lastBreakY = y; + this.lastBreakZ = z; + } + + public void handleTeleport() { + this.sinceBukkitTeleportTicks = 0; + } + + public void handleServerPosition(final WrappedPacketOutPosition wrapper) { + ++this.positionTransactionId; + ++this.positionPingId; + if (this.positionTransactionId > -28769) { + this.positionTransactionId = -29768; + } + if (this.positionPingId > -28769) { + this.positionPingId = -29768; + } + this.sinceTeleportTicks = 0; + final Vector teleport = new Vector(wrapper.getPosition().getX(), wrapper.getPosition().getY(), wrapper.getPosition().getZ()); + this.teleports.add(teleport); + if (ServerUtil.isHigherThan1_17()) { + this.data.sendPing(this.positionPingId); + } + else { + this.data.sendTransaction(this.positionTransactionId); + } + this.queuedTeleports.put(this.positionTransactionId, wrapper); + } + + public void handleEntityEffect(final WrappedPacketOutEntityEffect wrapper) { + ++this.entityEffectTransactionId; + ++this.entityEffectPingId; + if (this.entityEffectTransactionId > -27769) { + this.entityEffectTransactionId = -28768; + } + if (this.entityEffectPingId > -27769) { + this.entityEffectPingId = -28768; + } + if (ServerUtil.isHigherThan1_17()) { + this.data.sendPing(this.entityEffectPingId); + } + else { + this.data.sendTransaction(this.entityEffectTransactionId); + } + this.queuedEntityEffects.put(this.entityEffectTransactionId, wrapper); + } + + public void handleRemoveEntityEffect(final WrappedPacketOutRemoveEntityEffect wrapper) { + ++this.removeEntityEffectTransactionId; + ++this.removeEntityEffectPingId; + if (this.removeEntityEffectTransactionId > -26769) { + this.removeEntityEffectTransactionId = -27768; + } + if (this.removeEntityEffectPingId > -26769) { + this.removeEntityEffectPingId = -27768; + } + if (ServerUtil.isHigherThan1_17()) { + this.data.sendPing(this.removeEntityEffectPingId); + } + else { + this.data.sendTransaction(this.removeEntityEffectTransactionId); + } + this.queuedRemoveEntityEffects.put(this.removeEntityEffectTransactionId, wrapper); + } + + public void handleGameStateChange(final WrappedPacketOutGameStateChange wrapper) { + ++this.gameStateChangeTransactionId; + ++this.gameStateChangePingId; + if (this.gameStateChangeTransactionId > -25769) { + this.gameStateChangeTransactionId = -26768; + } + if (this.gameStateChangePingId > -25769) { + this.gameStateChangePingId = -26768; + } + if (ServerUtil.isHigherThan1_17()) { + this.data.sendPing(this.gameStateChangePingId); + } + else { + this.data.sendTransaction(this.gameStateChangeTransactionId); + } + this.queuedGameStateChanges.put(this.gameStateChangeTransactionId, wrapper); + } + + private void confirmPosition(final WrappedPacketInTransaction wrapper) { + if (this.queuedTeleports.containsKey(wrapper.getActionNumber())) { + final WrappedPacketOutPosition position = this.queuedTeleports.get(wrapper.getActionNumber()); + final Vector3d vector = position.getPosition(); + this.lastTeleportX = vector.getX(); + this.lastTeleportY = vector.getY(); + this.lastTeleportZ = vector.getZ(); + this.sinceTeleportTicks = 0; + this.queuedTeleports.remove(wrapper.getActionNumber()); + } + } + + public void confirmPositionPing(final WrappedPacketInPong wrapper) { + final short id = (short)wrapper.getId(); + if (this.queuedTeleports.containsKey(id)) { + final WrappedPacketOutPosition position = this.queuedTeleports.get(id); + final Vector3d vector = position.getPosition(); + this.lastTeleportX = vector.getX(); + this.lastTeleportY = vector.getY(); + this.lastTeleportZ = vector.getZ(); + this.sinceTeleportTicks = 0; + this.queuedTeleports.remove(id); + } + } + + private void confirmEntityEffect(final WrappedPacketInTransaction wrapper) { + if (this.queuedEntityEffects.containsKey(wrapper.getActionNumber())) { + final WrappedPacketOutEntityEffect confirmation = this.queuedEntityEffects.get(wrapper.getActionNumber()); + if (confirmation == null) { + return; + } + final int amplifier = confirmation.getAmplifier() + 1; + switch (confirmation.getEffectId()) { + case 1: { + this.speedAmplifier = amplifier; + this.hasSpeed = true; + break; + } + case 2: { + this.hasSlowness = true; + break; + } + case 8: { + this.jumpBoostAmplifier = amplifier; + this.hasJumpBoost = true; + break; + } + case 25: { + this.levitationAmplifier = amplifier; + this.hasLevitation = true; + break; + } + case 28: { + this.slowFallingAmplifier = amplifier; + this.hasSlowFalling = true; + break; + } + case 29: { + this.hasConduitsPower = true; + break; + } + case 30: { + this.dolphinsGraceAmplifier = amplifier; + this.hasDolphinsGrace = true; + break; + } + } + this.queuedEntityEffects.remove(wrapper.getActionNumber()); + } + } + + private void confirmEntityEffectPing(final WrappedPacketInPong wrapper) { + final short id = (short)wrapper.getId(); + if (this.queuedEntityEffects.containsKey(id)) { + final WrappedPacketOutEntityEffect confirmation = this.queuedEntityEffects.get(id); + final int amplifier = confirmation.getAmplifier() + 1; + switch (confirmation.getEffectId()) { + case 1: { + this.speedAmplifier = amplifier; + this.hasSpeed = true; + break; + } + case 8: { + this.jumpBoostAmplifier = amplifier; + this.hasJumpBoost = true; + break; + } + case 25: { + this.levitationAmplifier = amplifier; + this.hasLevitation = true; + break; + } + case 28: { + this.slowFallingAmplifier = amplifier; + this.hasSlowFalling = true; + break; + } + case 29: { + this.hasConduitsPower = true; + break; + } + case 30: { + this.dolphinsGraceAmplifier = amplifier; + this.hasDolphinsGrace = true; + break; + } + } + this.queuedEntityEffects.remove(id); + } + } + + private void confirmRemoveEntityEffectPing(final WrappedPacketInPong wrapper) { + final short id = (short)wrapper.getId(); + if (this.queuedRemoveEntityEffects.containsKey(id)) { + final WrappedPacketOutRemoveEntityEffect confirmation = this.queuedRemoveEntityEffects.get(id); + if (confirmation == null) { + return; + } + switch (confirmation.getEffectId()) { + case 1: { + this.speedAmplifier = 0; + this.hasSpeed = false; + this.data.getPositionProcessor().setSinceSpeedTicks(0); + break; + } + case 2: { + this.hasSlowness = false; + break; + } + case 8: { + this.jumpBoostAmplifier = 0; + this.hasJumpBoost = false; + break; + } + case 25: { + this.levitationAmplifier = 0; + this.hasLevitation = false; + break; + } + case 28: { + this.slowFallingAmplifier = 0; + this.hasSlowFalling = false; + break; + } + case 29: { + this.hasConduitsPower = false; + break; + } + case 30: { + this.dolphinsGraceAmplifier = 0; + this.hasDolphinsGrace = false; + break; + } + } + this.queuedRemoveEntityEffects.remove(id); + } + } + + private void confirmRemoveEntityEffect(final WrappedPacketInTransaction wrapper) { + if (this.queuedRemoveEntityEffects.containsKey(wrapper.getActionNumber())) { + final WrappedPacketOutRemoveEntityEffect confirmation = this.queuedRemoveEntityEffects.get(wrapper.getActionNumber()); + if (confirmation == null) { + return; + } + switch (confirmation.getEffectId()) { + case 1: { + this.speedAmplifier = 0; + this.hasSpeed = false; + this.data.getPositionProcessor().setSinceSpeedTicks(0); + break; + } + case 8: { + this.jumpBoostAmplifier = 0; + this.hasJumpBoost = false; + break; + } + case 25: { + this.levitationAmplifier = 0; + this.hasLevitation = false; + break; + } + case 28: { + this.slowFallingAmplifier = 0; + this.hasSlowFalling = false; + break; + } + case 29: { + this.hasConduitsPower = false; + break; + } + case 30: { + this.dolphinsGraceAmplifier = 0; + this.hasDolphinsGrace = false; + break; + } + } + this.queuedRemoveEntityEffects.remove(wrapper.getActionNumber()); + } + } + + private void confirmGameStateChangePing(final WrappedPacketInPong wrapper) { + final short id = (short)wrapper.getId(); + if (this.queuedGameStateChanges.containsKey(id)) { + final WrappedPacketOutGameStateChange confirmation = this.queuedGameStateChanges.get(id); + if (confirmation == null) { + return; + } + if (confirmation.getReason() == 3) { + switch ((int)confirmation.getValue()) { + case 0: { + this.gameMode = GameMode.SURVIVAL; + break; + } + case 1: { + this.gameMode = GameMode.CREATIVE; + break; + } + case 2: { + this.gameMode = GameMode.ADVENTURE; + break; + } + case 3: { + if (ServerUtil.isHigherThan1_7()) { + this.gameMode = GameMode.SPECTATOR; + break; + } + break; + } + } + } + this.queuedGameStateChanges.remove(id); + } + } + + private void confirmGameStateChange(final WrappedPacketInTransaction wrapper) { + if (this.queuedGameStateChanges.containsKey(wrapper.getActionNumber())) { + final WrappedPacketOutGameStateChange confirmation = this.queuedGameStateChanges.get(wrapper.getActionNumber()); + if (confirmation == null) { + return; + } + if (confirmation.getReason() == 3) { + switch ((int)confirmation.getValue()) { + case 0: { + this.gameMode = GameMode.SURVIVAL; + break; + } + case 1: { + this.gameMode = GameMode.CREATIVE; + break; + } + case 2: { + this.gameMode = GameMode.ADVENTURE; + break; + } + case 3: { + if (ServerUtil.isHigherThan1_7()) { + this.gameMode = GameMode.SPECTATOR; + break; + } + break; + } + } + } + this.queuedGameStateChanges.remove(wrapper.getActionNumber()); + } + } + + public void handlePong(final WrappedPacketInPong wrapper) { + this.confirmPositionPing(wrapper); + this.confirmEntityEffectPing(wrapper); + this.confirmGameStateChangePing(wrapper); + this.confirmRemoveEntityEffectPing(wrapper); + } + + public void handleTransaction(final WrappedPacketInTransaction wrapper) { + this.confirmPosition(wrapper); + this.confirmEntityEffect(wrapper); + this.confirmGameStateChange(wrapper); + this.confirmRemoveEntityEffect(wrapper); + } + + public void handleWorldChange() { + this.sinceWorldChangeTicks = 0; + this.data.getPositionProcessor().setServerAirTicks(0); + } + + public void handleDeath() { + this.sinceDeathTicks = 0; + } + + public void handleDamage(final EntityDamageEvent.DamageCause cause) { + this.lastDamage = Vulcan.INSTANCE.getTickManager().getTicks(); + this.sinceDamageTicks = 0; + if (cause != EntityDamageEvent.DamageCause.FALL && cause != EntityDamageEvent.DamageCause.SUFFOCATION) { + this.sinceNonFallDamageTicks = 0; + } + switch (cause) { + case SUFFOCATION: { + this.sinceSuffociationDamageTicks = 0; + break; + } + case ENTITY_EXPLOSION: + case BLOCK_EXPLOSION: { + this.sinceExplosionDamageTicks = 0; + break; + } + case ENTITY_ATTACK: { + this.sinceAttackDamageTicks = 0; + break; + } + case FIRE: + case FIRE_TICK: { + this.sinceFireDamageTicks = 0; + break; + } + case FALL: { + this.sinceFallDamageTicks = 0; + break; + } + case MAGIC: { + this.sinceMagicDamageTicks = 0; + break; + } + case POISON: { + this.sincePoisonDamageTicks = 0; + break; + } + case CONTACT: { + this.sinceContactDamageTicks = 0; + break; + } + case PROJECTILE: { + this.sinceProjectileDamageTicks = 0; + break; + } + case LAVA: { + this.sinceLavaDamageTicks = 0; + break; + } + } + } + + public void handleEnderPearl() { + this.sinceEnderPearlTicks = 0; + } + + public void handleBedEnter() { + this.lastBedEnter = Vulcan.INSTANCE.getTickManager().getTicks(); + } + + public void handleBedLeave() { + this.lastBedLeave = Vulcan.INSTANCE.getTickManager().getTicks(); + } + + public void handleFlying(final WrappedPacketInFlying wrapper) { + this.blocking = false; + this.sendingDig = false; + this.sendingAction = false; + this.placing = false; + ++this.ticksExisted; + ++this.sinceFireDamageTicks; + ++this.sinceMagicDamageTicks; + ++this.sinceFallDamageTicks; + ++this.sinceExplosionTicks; + ++this.sinceAttackDamageTicks; + ++this.sinceNonFallDamageTicks; + ++this.sinceContactDamageTicks; + ++this.sinceWitherDamageTicks; + ++this.sincePoisonDamageTicks; + ++this.sinceSuffociationDamageTicks; + ++this.sincePushTicks; + ++this.sinceProjectileDamageTicks; + ++this.sinceLavaDamageTicks; + ++this.sinceDragonDamageTicks; + ++this.sinceHoglinDamageTicks; + ++this.sinceStupidBucketEmptyTicks; + ++this.sinceExplosionDamageTicks; + ++this.sinceMythicMobTicks; + ++this.sinceBucketEmptyTicks; + ++this.sinceBlockPlaceTicks; + ++this.sinceIronGolemDamageTicks; + ++this.sinceGlassBottleFillTicks; + ++this.sinceClimbablePlaceTicks; + ++this.sinceSlimePlaceTicks; + ++this.sinceCrystalDamageTicks; + ++this.sinceWorldChangeTicks; + ++this.sinceRessurectTicks; + ++this.sinceBukkitTeleportTicks; + ++this.sinceDeathTicks; + ++this.sinceBerserkTicks; + ++this.sinceCrackshotDamageTicks; + ++this.sinceFireballDamageTicks; + ++this.sinceWebPlaceTicks; + ++this.sinceBukkitVelocityTicks; + ++this.sinceChorusFruitTeleportTicks; + ++this.sinceBowBoostTicks; + ++this.sinceEnderPearlTicks; + ++this.sinceCancelledPlaceTicks; + ++this.sinceAbilitiesTicks; + ++this.sinceDamageTicks; + ++this.sinceStartGlidingTicks; + ++this.sinceIcePlaceTicks; + ++this.sinceBlockBreakTicks; + ++this.sinceRavagerDamageTicks; + ++this.sinceNetherrackBreakTicks; + ++this.sinceTeleportTicks; + this.health = this.data.getPlayer().getHealth(); + if (wrapper.isMoving()) { + ++this.positionTicksExisted; + this.helmet = this.data.getPlayer().getInventory().getHelmet(); + this.chestplate = this.data.getPlayer().getInventory().getChestplate(); + this.leggings = this.data.getPlayer().getInventory().getLeggings(); + this.boots = this.data.getPlayer().getInventory().getBoots(); + this.itemInMainHand = this.data.getPlayer().getInventory().getItemInHand(); + if (ServerUtil.isHigherThan1_9()) { + this.itemInOffHand = this.data.getPlayer().getInventory().getItemInOffHand(); + } + if (ServerUtil.isHigherThan1_13()) { + if (this.helmet != null && this.helmet.hasItemMeta() && this.helmet.getItemMeta() != null && this.helmet.getItemMeta().hasAttributeModifiers()) { + this.data.getPositionProcessor().setSinceAttributeModifierTicks(0); + } + if (this.chestplate != null && this.chestplate.hasItemMeta() && this.chestplate.getItemMeta() != null && this.chestplate.getItemMeta().hasAttributeModifiers()) { + this.data.getPositionProcessor().setSinceAttributeModifierTicks(0); + } + if (this.leggings != null && this.leggings.hasItemMeta() && this.leggings.getItemMeta() != null && this.leggings.getItemMeta().hasAttributeModifiers()) { + this.data.getPositionProcessor().setSinceAttributeModifierTicks(0); + } + if (this.boots != null && this.boots.hasItemMeta() && this.boots.getItemMeta() != null && this.boots.getItemMeta().hasAttributeModifiers()) { + this.data.getPositionProcessor().setSinceAttributeModifierTicks(0); + } + if (this.itemInOffHand != null && this.itemInOffHand.hasItemMeta() && this.itemInOffHand.getItemMeta() != null && this.itemInOffHand.getItemMeta().hasAttributeModifiers()) { + this.data.getPositionProcessor().setSinceAttributeModifierTicks(0); + } + if (this.itemInMainHand != null && this.itemInMainHand.hasItemMeta() && this.itemInMainHand.getItemMeta() != null && this.itemInMainHand.getItemMeta().hasAttributeModifiers()) { + this.data.getPositionProcessor().setSinceAttributeModifierTicks(0); + } + } + this.wearingDepthStrider = (ServerUtil.isHigherThan1_7() && this.boots != null && this.boots.containsEnchantment(Enchantment.DEPTH_STRIDER)); + this.wearingElytra = (ServerUtil.isHigherThan1_9() && this.chestplate != null && this.chestplate.getType().toString().equals("ELYTRA")); + this.bukkitGliding = PlayerUtil.isGliding(this.data.getPlayer()); + if (this.bukkitGliding) { + this.lastGlidingDeltaXZ = this.data.getPositionProcessor().getDeltaXZ(); + } + this.teleporting = false; + final double x = wrapper.getX(); + final double y = wrapper.getY(); + final double z = wrapper.getZ(); + if (this.sprinting) { + ++this.sprintingTicks; + } + else { + this.sprintingTicks = 0; + } + if (!this.sprinting) { + ++this.sinceSprintingTicks; + } + else { + this.sinceSprintingTicks = 0; + } + if (this.lastBreakX != 0.0 && this.lastBreakZ != 0.0) { + this.distanceFromLastBreak = MathUtil.magnitude(Math.abs(x - this.lastBreakX), Math.abs(y - this.lastBreakY), Math.abs(z - this.lastBreakZ)); + if (this.distanceFromLastBreak > 8.0) { + final double lastBreakX = 0.0; + this.distanceFromLastBreak = lastBreakX; + this.lastBreakZ = lastBreakX; + this.lastBreakX = lastBreakX; + } + } + if (this.lastScaffoldPlaceX != 0 && this.lastScaffoldPlaceY != 0 && this.lastScaffoldPlaceZ != 0) { + this.distanceFromLastScaffoldPlace = MathUtil.magnitude(Math.abs(x - this.lastScaffoldPlaceX), Math.abs(y - this.lastScaffoldPlaceY), Math.abs(z - this.lastScaffoldPlaceZ)); + if (this.distanceFromLastScaffoldPlace > 12.0) { + final int lastScaffoldPlaceX = 0; + this.lastScaffoldPlaceZ = lastScaffoldPlaceX; + this.lastScaffoldPlaceY = lastScaffoldPlaceX; + this.lastScaffoldPlaceX = lastScaffoldPlaceX; + } + } + for (final Vector teleport : this.teleports) { + final double deltaX = Math.abs(teleport.getX() - x); + final double deltaY = Math.abs(teleport.getY() - y); + final double deltaZ = Math.abs(teleport.getZ() - z); + if (deltaX <= 0.03 && deltaY <= 0.03 && deltaZ <= 0.03) { + this.teleporting = true; + } + } + } + } + + public void handleSlimePlace() { + this.sinceSlimePlaceTicks = 0; + } + + public void handleCancelledPlace() { + this.sinceCancelledPlaceTicks = 0; + } + + public void handleIcePlace() { + this.sinceIcePlaceTicks = 0; + } + + public void handleBukkitVelocity() { + this.sinceBukkitVelocityTicks = 0; + } + + public void handleClimbablePlace() { + this.sinceClimbablePlaceTicks = 0; + } + + public void handleWebPlace() { + this.sinceWebPlaceTicks = 0; + } + + public void handleProjectileThrow() { + this.lastProjectileThrow = Vulcan.INSTANCE.getTickManager().getTicks(); + } + + public void handleFishEvent() { + this.lastFishEvent = Vulcan.INSTANCE.getTickManager().getTicks(); + } + + public void handleAbilities(final WrappedPacketOutAbilities wrapper) { + this.sinceAbilitiesTicks = 0; + } + + public void handleResurrect() { + this.sinceRessurectTicks = 0; + } + + public void handleScaffoldingPlace(final BlockPlaceEvent event) { + this.lastScaffoldPlaceX = event.getBlockPlaced().getX(); + this.lastScaffoldPlaceY = event.getBlockPlaced().getY(); + this.lastScaffoldPlaceZ = event.getBlockPlaced().getZ(); + } + + public void handleCrackshotDamage() { + this.sinceCrackshotDamageTicks = 0; + } + + public void handleChorusEat() { + this.sinceChorusFruitTeleportTicks = 0; + } + + public void handleMetaData(final WrappedPacketOutEntityMetadata wrapper) { + final WrappedWatchableObject watchable = this.getIndex(wrapper.getWatchableObjects(), 0); + if (watchable != null) { + final Object zeroBitField = watchable.getRawValue(); + if (zeroBitField instanceof Byte) { + final byte field = (byte)zeroBitField; + this.packetGliding = (PlayerUtil.isHigherThan1_9(this.data.getPlayer()) && (field & 0x80) == 0x80); + this.packetSwimming = ((field & 0x10) == 0x10); + } + } + } + + private WrappedWatchableObject getIndex(final List objects, final int index) { + for (final WrappedWatchableObject object : objects) { + if (object.getIndex() == index) { + return object; + } + } + return null; + } + + public void handleExplosion(final WrappedPacketOutExplosion wrapper) { + final Vector3f velocity = wrapper.getPlayerVelocity(); + this.explosionX = velocity.getX(); + this.explosionY = velocity.getY(); + this.explosionZ = velocity.getZ(); + this.sinceExplosionTicks = 0; + } + + public void onJoin() { + this.hasSpeed = this.data.getPlayer().hasPotionEffect(PotionEffectType.SPEED); + if (this.hasSpeed) { + if (ServerUtil.isHigherThan1_13()) { + this.speedAmplifier = this.data.getPlayer().getPotionEffect(PotionEffectType.SPEED).getAmplifier() + 1; + } + else { + this.speedAmplifier = PlayerUtil.getPotionLevel(this.data.getPlayer(), PotionEffectType.SPEED); + } + } + this.hasSlowness = this.data.getPlayer().hasPotionEffect(PotionEffectType.SLOW); + this.hasJumpBoost = this.data.getPlayer().hasPotionEffect(PotionEffectType.JUMP); + if (this.hasJumpBoost) { + if (ServerUtil.isHigherThan1_13()) { + this.jumpBoostAmplifier = this.data.getPlayer().getPotionEffect(PotionEffectType.JUMP).getAmplifier() + 1; + } + else { + this.jumpBoostAmplifier = PlayerUtil.getPotionLevel(this.data.getPlayer(), PotionEffectType.JUMP); + } + } + if (ServerUtil.isHigherThan1_11()) { + this.hasLevitation = this.data.getPlayer().hasPotionEffect(PotionEffectType.LEVITATION); + if (this.hasLevitation) { + if (ServerUtil.isHigherThan1_13()) { + this.levitationAmplifier = this.data.getPlayer().getPotionEffect(PotionEffectType.LEVITATION).getAmplifier() + 1; + } + else { + this.levitationAmplifier = PlayerUtil.getPotionLevel(this.data.getPlayer(), PotionEffectType.LEVITATION); + } + } + } + if (ServerUtil.isHigherThan1_13()) { + this.hasDolphinsGrace = this.data.getPlayer().hasPotionEffect(PotionEffectType.DOLPHINS_GRACE); + if (this.hasDolphinsGrace) { + this.dolphinsGraceAmplifier = this.data.getPlayer().getPotionEffect(PotionEffectType.DOLPHINS_GRACE).getAmplifier() + 1; + } + this.hasConduitsPower = this.data.getPlayer().hasPotionEffect(PotionEffectType.CONDUIT_POWER); + this.hasSlowFalling = this.data.getPlayer().hasPotionEffect(PotionEffectType.SLOW_FALLING); + if (this.hasSlowFalling) { + this.slowFallingAmplifier = this.data.getPlayer().getPotionEffect(PotionEffectType.SLOW_FALLING).getAmplifier() + 1; + } + } + } + + public PlayerData getData() { + return this.data; + } + + public boolean isSprinting() { + return this.sprinting; + } + + public boolean isSneaking() { + return this.sneaking; + } + + public boolean isSendingAction() { + return this.sendingAction; + } + + public boolean isPlacing() { + return this.placing; + } + + public boolean isDigging() { + return this.digging; + } + + public boolean isBlocking() { + return this.blocking; + } + + public boolean isInventory() { + return this.inventory; + } + + public boolean isSendingDig() { + return this.sendingDig; + } + + public boolean isTeleporting() { + return this.teleporting; + } + + public boolean isHasSpeed() { + return this.hasSpeed; + } + + public boolean isHasJumpBoost() { + return this.hasJumpBoost; + } + + public boolean isHasLevitation() { + return this.hasLevitation; + } + + public boolean isHasSlowFalling() { + return this.hasSlowFalling; + } + + public boolean isHasDolphinsGrace() { + return this.hasDolphinsGrace; + } + + public boolean isSitting() { + return this.sitting; + } + + public boolean isHasConduitsPower() { + return this.hasConduitsPower; + } + + public boolean isCrawling() { + return this.crawling; + } + + public boolean isHasSlowness() { + return this.hasSlowness; + } + + public boolean isWearingDepthStrider() { + return this.wearingDepthStrider; + } + + public boolean isWearingElytra() { + return this.wearingElytra; + } + + public boolean isBukkitGliding() { + return this.bukkitGliding; + } + + public boolean isPacketGliding() { + return this.packetGliding; + } + + public boolean isPacketSwimming() { + return this.packetSwimming; + } + + public boolean isUpdateSwim() { + return this.updateSwim; + } + + public double getGenericMovementSpeed() { + return this.genericMovementSpeed; + } + + public boolean isBerserking() { + return this.berserking; + } + + public int getLastBukkitDiggingTick() { + return this.lastBukkitDiggingTick; + } + + public int getLastDropItemTick() { + return this.lastDropItemTick; + } + + public int getLastDiggingTick() { + return this.lastDiggingTick; + } + + public int getSinceSprintingTicks() { + return this.sinceSprintingTicks; + } + + public int getPositionTicksExisted() { + return this.positionTicksExisted; + } + + public int getLastWindowClick() { + return this.lastWindowClick; + } + + public int getAmount() { + return this.amount; + } + + public int getLastAmount() { + return this.lastAmount; + } + + public int getSlot() { + return this.slot; + } + + public int getLastSlot() { + return this.lastSlot; + } + + public int getSinceTeleportTicks() { + return this.sinceTeleportTicks; + } + + public int getSinceExplosionTicks() { + return this.sinceExplosionTicks; + } + + public int getLastBedEnter() { + return this.lastBedEnter; + } + + public int getLastBedLeave() { + return this.lastBedLeave; + } + + public int getLastItemPickup() { + return this.lastItemPickup; + } + + public int getLastCancelledBreak() { + return this.lastCancelledBreak; + } + + public int getLastChorusFruitTeleport() { + return this.lastChorusFruitTeleport; + } + + public int getLastDamage() { + return this.lastDamage; + } + + public int getSinceDragonDamageTicks() { + return this.sinceDragonDamageTicks; + } + + public int getSprintingTicks() { + return this.sprintingTicks; + } + + public int getLastRespawn() { + return this.lastRespawn; + } + + public int getLastLowHealth() { + return this.lastLowHealth; + } + + public int getLastProjectileThrow() { + return this.lastProjectileThrow; + } + + public int getLastFishEvent() { + return this.lastFishEvent; + } + + public int getSinceFireDamageTicks() { + return this.sinceFireDamageTicks; + } + + public int getSinceAttackDamageTicks() { + return this.sinceAttackDamageTicks; + } + + public int getSinceFallDamageTicks() { + return this.sinceFallDamageTicks; + } + + public int getSinceMagicDamageTicks() { + return this.sinceMagicDamageTicks; + } + + public int getSincePoisonDamageTicks() { + return this.sincePoisonDamageTicks; + } + + public int getSinceContactDamageTicks() { + return this.sinceContactDamageTicks; + } + + public int getSinceProjectileDamageTicks() { + return this.sinceProjectileDamageTicks; + } + + public int getLastLavaDamage() { + return this.lastLavaDamage; + } + + public int getSinceLavaDamageTicks() { + return this.sinceLavaDamageTicks; + } + + public int getSinceExplosionDamageTicks() { + return this.sinceExplosionDamageTicks; + } + + public int getSinceBucketEmptyTicks() { + return this.sinceBucketEmptyTicks; + } + + public int getSinceBlockPlaceTicks() { + return this.sinceBlockPlaceTicks; + } + + public int getSinceClimbablePlaceTicks() { + return this.sinceClimbablePlaceTicks; + } + + public int getSinceSlimePlaceTicks() { + return this.sinceSlimePlaceTicks; + } + + public int getSinceCancelledPlaceTicks() { + return this.sinceCancelledPlaceTicks; + } + + public int getSinceWorldChangeTicks() { + return this.sinceWorldChangeTicks; + } + + public int getSinceRessurectTicks() { + return this.sinceRessurectTicks; + } + + public int getSinceBukkitTeleportTicks() { + return this.sinceBukkitTeleportTicks; + } + + public int getSinceDeathTicks() { + return this.sinceDeathTicks; + } + + public int getSinceNonFallDamageTicks() { + return this.sinceNonFallDamageTicks; + } + + public int getSinceIronGolemDamageTicks() { + return this.sinceIronGolemDamageTicks; + } + + public int getLastScaffoldPlaceX() { + return this.lastScaffoldPlaceX; + } + + public int getLastScaffoldPlaceY() { + return this.lastScaffoldPlaceY; + } + + public int getLastScaffoldPlaceZ() { + return this.lastScaffoldPlaceZ; + } + + public int getSinceBerserkTicks() { + return this.sinceBerserkTicks; + } + + public int getSinceCrackshotDamageTicks() { + return this.sinceCrackshotDamageTicks; + } + + public int getSinceGlassBottleFillTicks() { + return this.sinceGlassBottleFillTicks; + } + + public int getSinceFireballDamageTicks() { + return this.sinceFireballDamageTicks; + } + + public int getSpeedAmplifier() { + return this.speedAmplifier; + } + + public int getJumpBoostAmplifier() { + return this.jumpBoostAmplifier; + } + + public int getLevitationAmplifier() { + return this.levitationAmplifier; + } + + public int getSlowFallingAmplifier() { + return this.slowFallingAmplifier; + } + + public int getDolphinsGraceAmplifier() { + return this.dolphinsGraceAmplifier; + } + + public int getSinceChorusFruitTeleportTicks() { + return this.sinceChorusFruitTeleportTicks; + } + + public int getSinceWebPlaceTicks() { + return this.sinceWebPlaceTicks; + } + + public int getSinceEnderPearlTicks() { + return this.sinceEnderPearlTicks; + } + + public int getSinceBukkitVelocityTicks() { + return this.sinceBukkitVelocityTicks; + } + + public int getSinceDamageTicks() { + return this.sinceDamageTicks; + } + + public int getSinceStartGlidingTicks() { + return this.sinceStartGlidingTicks; + } + + public int getSinceIcePlaceTicks() { + return this.sinceIcePlaceTicks; + } + + public int getSinceBlockBreakTicks() { + return this.sinceBlockBreakTicks; + } + + public int getTicksExisted() { + return this.ticksExisted; + } + + public int getSinceHoglinDamageTicks() { + return this.sinceHoglinDamageTicks; + } + + public int getSinceAbilitiesTicks() { + return this.sinceAbilitiesTicks; + } + + public int getSincePushTicks() { + return this.sincePushTicks; + } + + public int getSinceMythicMobTicks() { + return this.sinceMythicMobTicks; + } + + public int getSinceCancelledMoveTicks() { + return this.sinceCancelledMoveTicks; + } + + public int getSinceRavagerDamageTicks() { + return this.sinceRavagerDamageTicks; + } + + public int getSinceWitherDamageTicks() { + return this.sinceWitherDamageTicks; + } + + public int getSinceCrystalDamageTicks() { + return this.sinceCrystalDamageTicks; + } + + public int getSinceSuffociationDamageTicks() { + return this.sinceSuffociationDamageTicks; + } + + public int getSinceStupidBucketEmptyTicks() { + return this.sinceStupidBucketEmptyTicks; + } + + public int getSinceNetherrackBreakTicks() { + return this.sinceNetherrackBreakTicks; + } + + public int getSinceBowBoostTicks() { + return this.sinceBowBoostTicks; + } + + public double getLastAbortX() { + return this.lastAbortX; + } + + public double getLastAbortZ() { + return this.lastAbortZ; + } + + public double getDistanceFromLastAbort() { + return this.distanceFromLastAbort; + } + + public double getLastBreakX() { + return this.lastBreakX; + } + + public double getLastBreakY() { + return this.lastBreakY; + } + + public double getLastBreakZ() { + return this.lastBreakZ; + } + + public double getDistanceFromLastBreak() { + return this.distanceFromLastBreak; + } + + public double getHealth() { + return this.health; + } + + public double getDistanceFromLastScaffoldPlace() { + return this.distanceFromLastScaffoldPlace; + } + + public double getExplosionX() { + return this.explosionX; + } + + public double getExplosionY() { + return this.explosionY; + } + + public double getExplosionZ() { + return this.explosionZ; + } + + public double getLastTeleportX() { + return this.lastTeleportX; + } + + public double getLastTeleportY() { + return this.lastTeleportY; + } + + public double getLastTeleportZ() { + return this.lastTeleportZ; + } + + public double getDistanceFromLastTeleport() { + return this.distanceFromLastTeleport; + } + + public double getLastGlidingDeltaXZ() { + return this.lastGlidingDeltaXZ; + } + + public long getLastStartDestroy() { + return this.lastStartDestroy; + } + + public long getLastStopDestroy() { + return this.lastStopDestroy; + } + + public long getLastAbort() { + return this.lastAbort; + } + + public GameMode getGameMode() { + return this.gameMode; + } + + public short getPositionTransactionId() { + return this.positionTransactionId; + } + + public short getEntityEffectTransactionId() { + return this.entityEffectTransactionId; + } + + public short getRemoveEntityEffectTransactionId() { + return this.removeEntityEffectTransactionId; + } + + public short getGameStateChangeTransactionId() { + return this.gameStateChangeTransactionId; + } + + public short getPositionPingId() { + return this.positionPingId; + } + + public short getEntityEffectPingId() { + return this.entityEffectPingId; + } + + public short getRemoveEntityEffectPingId() { + return this.removeEntityEffectPingId; + } + + public short getGameStateChangePingId() { + return this.gameStateChangePingId; + } + + public Map getQueuedEntityEffects() { + return this.queuedEntityEffects; + } + + public Map getQueuedRemoveEntityEffects() { + return this.queuedRemoveEntityEffects; + } + + public Map getQueuedGameStateChanges() { + return this.queuedGameStateChanges; + } + + public Map getQueuedTeleports() { + return this.queuedTeleports; + } + + public ItemStack getHelmet() { + return this.helmet; + } + + public ItemStack getChestplate() { + return this.chestplate; + } + + public ItemStack getLeggings() { + return this.leggings; + } + + public ItemStack getBoots() { + return this.boots; + } + + public ItemStack getItemInMainHand() { + return this.itemInMainHand; + } + + public ItemStack getItemInOffHand() { + return this.itemInOffHand; + } + + public EvictingList getTeleports() { + return this.teleports; + } + + public void setSprinting(final boolean sprinting) { + this.sprinting = sprinting; + } + + public void setSneaking(final boolean sneaking) { + this.sneaking = sneaking; + } + + public void setSendingAction(final boolean sendingAction) { + this.sendingAction = sendingAction; + } + + public void setPlacing(final boolean placing) { + this.placing = placing; + } + + public void setDigging(final boolean digging) { + this.digging = digging; + } + + public void setBlocking(final boolean blocking) { + this.blocking = blocking; + } + + public void setInventory(final boolean inventory) { + this.inventory = inventory; + } + + public void setSendingDig(final boolean sendingDig) { + this.sendingDig = sendingDig; + } + + public void setTeleporting(final boolean teleporting) { + this.teleporting = teleporting; + } + + public void setHasSpeed(final boolean hasSpeed) { + this.hasSpeed = hasSpeed; + } + + public void setHasJumpBoost(final boolean hasJumpBoost) { + this.hasJumpBoost = hasJumpBoost; + } + + public void setHasLevitation(final boolean hasLevitation) { + this.hasLevitation = hasLevitation; + } + + public void setHasSlowFalling(final boolean hasSlowFalling) { + this.hasSlowFalling = hasSlowFalling; + } + + public void setHasDolphinsGrace(final boolean hasDolphinsGrace) { + this.hasDolphinsGrace = hasDolphinsGrace; + } + + public void setSitting(final boolean sitting) { + this.sitting = sitting; + } + + public void setHasConduitsPower(final boolean hasConduitsPower) { + this.hasConduitsPower = hasConduitsPower; + } + + public void setCrawling(final boolean crawling) { + this.crawling = crawling; + } + + public void setHasSlowness(final boolean hasSlowness) { + this.hasSlowness = hasSlowness; + } + + public void setWearingDepthStrider(final boolean wearingDepthStrider) { + this.wearingDepthStrider = wearingDepthStrider; + } + + public void setWearingElytra(final boolean wearingElytra) { + this.wearingElytra = wearingElytra; + } + + public void setBukkitGliding(final boolean bukkitGliding) { + this.bukkitGliding = bukkitGliding; + } + + public void setPacketGliding(final boolean packetGliding) { + this.packetGliding = packetGliding; + } + + public void setPacketSwimming(final boolean packetSwimming) { + this.packetSwimming = packetSwimming; + } + + public void setUpdateSwim(final boolean updateSwim) { + this.updateSwim = updateSwim; + } + + public void setGenericMovementSpeed(final double genericMovementSpeed) { + this.genericMovementSpeed = genericMovementSpeed; + } + + public void setLastBukkitDiggingTick(final int lastBukkitDiggingTick) { + this.lastBukkitDiggingTick = lastBukkitDiggingTick; + } + + public void setLastDropItemTick(final int lastDropItemTick) { + this.lastDropItemTick = lastDropItemTick; + } + + public void setLastDiggingTick(final int lastDiggingTick) { + this.lastDiggingTick = lastDiggingTick; + } + + public void setSinceSprintingTicks(final int sinceSprintingTicks) { + this.sinceSprintingTicks = sinceSprintingTicks; + } + + public void setPositionTicksExisted(final int positionTicksExisted) { + this.positionTicksExisted = positionTicksExisted; + } + + public void setLastWindowClick(final int lastWindowClick) { + this.lastWindowClick = lastWindowClick; + } + + public void setAmount(final int amount) { + this.amount = amount; + } + + public void setLastAmount(final int lastAmount) { + this.lastAmount = lastAmount; + } + + public void setSlot(final int slot) { + this.slot = slot; + } + + public void setLastSlot(final int lastSlot) { + this.lastSlot = lastSlot; + } + + public void setSinceTeleportTicks(final int sinceTeleportTicks) { + this.sinceTeleportTicks = sinceTeleportTicks; + } + + public void setSinceExplosionTicks(final int sinceExplosionTicks) { + this.sinceExplosionTicks = sinceExplosionTicks; + } + + public void setLastBedEnter(final int lastBedEnter) { + this.lastBedEnter = lastBedEnter; + } + + public void setLastBedLeave(final int lastBedLeave) { + this.lastBedLeave = lastBedLeave; + } + + public void setLastItemPickup(final int lastItemPickup) { + this.lastItemPickup = lastItemPickup; + } + + public void setLastCancelledBreak(final int lastCancelledBreak) { + this.lastCancelledBreak = lastCancelledBreak; + } + + public void setLastChorusFruitTeleport(final int lastChorusFruitTeleport) { + this.lastChorusFruitTeleport = lastChorusFruitTeleport; + } + + public void setLastDamage(final int lastDamage) { + this.lastDamage = lastDamage; + } + + public void setSinceDragonDamageTicks(final int sinceDragonDamageTicks) { + this.sinceDragonDamageTicks = sinceDragonDamageTicks; + } + + public void setSprintingTicks(final int sprintingTicks) { + this.sprintingTicks = sprintingTicks; + } + + public void setLastRespawn(final int lastRespawn) { + this.lastRespawn = lastRespawn; + } + + public void setLastLowHealth(final int lastLowHealth) { + this.lastLowHealth = lastLowHealth; + } + + public void setLastProjectileThrow(final int lastProjectileThrow) { + this.lastProjectileThrow = lastProjectileThrow; + } + + public void setLastFishEvent(final int lastFishEvent) { + this.lastFishEvent = lastFishEvent; + } + + public void setSinceFireDamageTicks(final int sinceFireDamageTicks) { + this.sinceFireDamageTicks = sinceFireDamageTicks; + } + + public void setSinceAttackDamageTicks(final int sinceAttackDamageTicks) { + this.sinceAttackDamageTicks = sinceAttackDamageTicks; + } + + public void setSinceFallDamageTicks(final int sinceFallDamageTicks) { + this.sinceFallDamageTicks = sinceFallDamageTicks; + } + + public void setSinceMagicDamageTicks(final int sinceMagicDamageTicks) { + this.sinceMagicDamageTicks = sinceMagicDamageTicks; + } + + public void setSincePoisonDamageTicks(final int sincePoisonDamageTicks) { + this.sincePoisonDamageTicks = sincePoisonDamageTicks; + } + + public void setSinceContactDamageTicks(final int sinceContactDamageTicks) { + this.sinceContactDamageTicks = sinceContactDamageTicks; + } + + public void setSinceProjectileDamageTicks(final int sinceProjectileDamageTicks) { + this.sinceProjectileDamageTicks = sinceProjectileDamageTicks; + } + + public void setLastLavaDamage(final int lastLavaDamage) { + this.lastLavaDamage = lastLavaDamage; + } + + public void setSinceLavaDamageTicks(final int sinceLavaDamageTicks) { + this.sinceLavaDamageTicks = sinceLavaDamageTicks; + } + + public void setSinceExplosionDamageTicks(final int sinceExplosionDamageTicks) { + this.sinceExplosionDamageTicks = sinceExplosionDamageTicks; + } + + public void setSinceBucketEmptyTicks(final int sinceBucketEmptyTicks) { + this.sinceBucketEmptyTicks = sinceBucketEmptyTicks; + } + + public void setSinceBlockPlaceTicks(final int sinceBlockPlaceTicks) { + this.sinceBlockPlaceTicks = sinceBlockPlaceTicks; + } + + public void setSinceClimbablePlaceTicks(final int sinceClimbablePlaceTicks) { + this.sinceClimbablePlaceTicks = sinceClimbablePlaceTicks; + } + + public void setSinceSlimePlaceTicks(final int sinceSlimePlaceTicks) { + this.sinceSlimePlaceTicks = sinceSlimePlaceTicks; + } + + public void setSinceCancelledPlaceTicks(final int sinceCancelledPlaceTicks) { + this.sinceCancelledPlaceTicks = sinceCancelledPlaceTicks; + } + + public void setSinceWorldChangeTicks(final int sinceWorldChangeTicks) { + this.sinceWorldChangeTicks = sinceWorldChangeTicks; + } + + public void setSinceRessurectTicks(final int sinceRessurectTicks) { + this.sinceRessurectTicks = sinceRessurectTicks; + } + + public void setSinceBukkitTeleportTicks(final int sinceBukkitTeleportTicks) { + this.sinceBukkitTeleportTicks = sinceBukkitTeleportTicks; + } + + public void setSinceDeathTicks(final int sinceDeathTicks) { + this.sinceDeathTicks = sinceDeathTicks; + } + + public void setSinceNonFallDamageTicks(final int sinceNonFallDamageTicks) { + this.sinceNonFallDamageTicks = sinceNonFallDamageTicks; + } + + public void setSinceIronGolemDamageTicks(final int sinceIronGolemDamageTicks) { + this.sinceIronGolemDamageTicks = sinceIronGolemDamageTicks; + } + + public void setLastScaffoldPlaceX(final int lastScaffoldPlaceX) { + this.lastScaffoldPlaceX = lastScaffoldPlaceX; + } + + public void setLastScaffoldPlaceY(final int lastScaffoldPlaceY) { + this.lastScaffoldPlaceY = lastScaffoldPlaceY; + } + + public void setLastScaffoldPlaceZ(final int lastScaffoldPlaceZ) { + this.lastScaffoldPlaceZ = lastScaffoldPlaceZ; + } + + public void setSinceBerserkTicks(final int sinceBerserkTicks) { + this.sinceBerserkTicks = sinceBerserkTicks; + } + + public void setSinceCrackshotDamageTicks(final int sinceCrackshotDamageTicks) { + this.sinceCrackshotDamageTicks = sinceCrackshotDamageTicks; + } + + public void setSinceGlassBottleFillTicks(final int sinceGlassBottleFillTicks) { + this.sinceGlassBottleFillTicks = sinceGlassBottleFillTicks; + } + + public void setSinceFireballDamageTicks(final int sinceFireballDamageTicks) { + this.sinceFireballDamageTicks = sinceFireballDamageTicks; + } + + public void setSpeedAmplifier(final int speedAmplifier) { + this.speedAmplifier = speedAmplifier; + } + + public void setJumpBoostAmplifier(final int jumpBoostAmplifier) { + this.jumpBoostAmplifier = jumpBoostAmplifier; + } + + public void setLevitationAmplifier(final int levitationAmplifier) { + this.levitationAmplifier = levitationAmplifier; + } + + public void setSlowFallingAmplifier(final int slowFallingAmplifier) { + this.slowFallingAmplifier = slowFallingAmplifier; + } + + public void setDolphinsGraceAmplifier(final int dolphinsGraceAmplifier) { + this.dolphinsGraceAmplifier = dolphinsGraceAmplifier; + } + + public void setSinceChorusFruitTeleportTicks(final int sinceChorusFruitTeleportTicks) { + this.sinceChorusFruitTeleportTicks = sinceChorusFruitTeleportTicks; + } + + public void setSinceWebPlaceTicks(final int sinceWebPlaceTicks) { + this.sinceWebPlaceTicks = sinceWebPlaceTicks; + } + + public void setSinceEnderPearlTicks(final int sinceEnderPearlTicks) { + this.sinceEnderPearlTicks = sinceEnderPearlTicks; + } + + public void setSinceBukkitVelocityTicks(final int sinceBukkitVelocityTicks) { + this.sinceBukkitVelocityTicks = sinceBukkitVelocityTicks; + } + + public void setSinceDamageTicks(final int sinceDamageTicks) { + this.sinceDamageTicks = sinceDamageTicks; + } + + public void setSinceStartGlidingTicks(final int sinceStartGlidingTicks) { + this.sinceStartGlidingTicks = sinceStartGlidingTicks; + } + + public void setSinceIcePlaceTicks(final int sinceIcePlaceTicks) { + this.sinceIcePlaceTicks = sinceIcePlaceTicks; + } + + public void setSinceBlockBreakTicks(final int sinceBlockBreakTicks) { + this.sinceBlockBreakTicks = sinceBlockBreakTicks; + } + + public void setTicksExisted(final int ticksExisted) { + this.ticksExisted = ticksExisted; + } + + public void setSinceHoglinDamageTicks(final int sinceHoglinDamageTicks) { + this.sinceHoglinDamageTicks = sinceHoglinDamageTicks; + } + + public void setSinceAbilitiesTicks(final int sinceAbilitiesTicks) { + this.sinceAbilitiesTicks = sinceAbilitiesTicks; + } + + public void setSincePushTicks(final int sincePushTicks) { + this.sincePushTicks = sincePushTicks; + } + + public void setSinceMythicMobTicks(final int sinceMythicMobTicks) { + this.sinceMythicMobTicks = sinceMythicMobTicks; + } + + public void setSinceCancelledMoveTicks(final int sinceCancelledMoveTicks) { + this.sinceCancelledMoveTicks = sinceCancelledMoveTicks; + } + + public void setSinceRavagerDamageTicks(final int sinceRavagerDamageTicks) { + this.sinceRavagerDamageTicks = sinceRavagerDamageTicks; + } + + public void setSinceWitherDamageTicks(final int sinceWitherDamageTicks) { + this.sinceWitherDamageTicks = sinceWitherDamageTicks; + } + + public void setSinceCrystalDamageTicks(final int sinceCrystalDamageTicks) { + this.sinceCrystalDamageTicks = sinceCrystalDamageTicks; + } + + public void setSinceSuffociationDamageTicks(final int sinceSuffociationDamageTicks) { + this.sinceSuffociationDamageTicks = sinceSuffociationDamageTicks; + } + + public void setSinceStupidBucketEmptyTicks(final int sinceStupidBucketEmptyTicks) { + this.sinceStupidBucketEmptyTicks = sinceStupidBucketEmptyTicks; + } + + public void setSinceNetherrackBreakTicks(final int sinceNetherrackBreakTicks) { + this.sinceNetherrackBreakTicks = sinceNetherrackBreakTicks; + } + + public void setSinceBowBoostTicks(final int sinceBowBoostTicks) { + this.sinceBowBoostTicks = sinceBowBoostTicks; + } + + public void setLastAbortX(final double lastAbortX) { + this.lastAbortX = lastAbortX; + } + + public void setLastAbortZ(final double lastAbortZ) { + this.lastAbortZ = lastAbortZ; + } + + public void setDistanceFromLastAbort(final double distanceFromLastAbort) { + this.distanceFromLastAbort = distanceFromLastAbort; + } + + public void setLastBreakX(final double lastBreakX) { + this.lastBreakX = lastBreakX; + } + + public void setLastBreakY(final double lastBreakY) { + this.lastBreakY = lastBreakY; + } + + public void setLastBreakZ(final double lastBreakZ) { + this.lastBreakZ = lastBreakZ; + } + + public void setDistanceFromLastBreak(final double distanceFromLastBreak) { + this.distanceFromLastBreak = distanceFromLastBreak; + } + + public void setHealth(final double health) { + this.health = health; + } + + public void setDistanceFromLastScaffoldPlace(final double distanceFromLastScaffoldPlace) { + this.distanceFromLastScaffoldPlace = distanceFromLastScaffoldPlace; + } + + public void setExplosionX(final double explosionX) { + this.explosionX = explosionX; + } + + public void setExplosionY(final double explosionY) { + this.explosionY = explosionY; + } + + public void setExplosionZ(final double explosionZ) { + this.explosionZ = explosionZ; + } + + public void setLastTeleportX(final double lastTeleportX) { + this.lastTeleportX = lastTeleportX; + } + + public void setLastTeleportY(final double lastTeleportY) { + this.lastTeleportY = lastTeleportY; + } + + public void setLastTeleportZ(final double lastTeleportZ) { + this.lastTeleportZ = lastTeleportZ; + } + + public void setDistanceFromLastTeleport(final double distanceFromLastTeleport) { + this.distanceFromLastTeleport = distanceFromLastTeleport; + } + + public void setLastGlidingDeltaXZ(final double lastGlidingDeltaXZ) { + this.lastGlidingDeltaXZ = lastGlidingDeltaXZ; + } + + public void setLastStartDestroy(final long lastStartDestroy) { + this.lastStartDestroy = lastStartDestroy; + } + + public void setLastStopDestroy(final long lastStopDestroy) { + this.lastStopDestroy = lastStopDestroy; + } + + public void setLastAbort(final long lastAbort) { + this.lastAbort = lastAbort; + } + + public void setGameMode(final GameMode gameMode) { + this.gameMode = gameMode; + } + + public void setPositionTransactionId(final short positionTransactionId) { + this.positionTransactionId = positionTransactionId; + } + + public void setEntityEffectTransactionId(final short entityEffectTransactionId) { + this.entityEffectTransactionId = entityEffectTransactionId; + } + + public void setRemoveEntityEffectTransactionId(final short removeEntityEffectTransactionId) { + this.removeEntityEffectTransactionId = removeEntityEffectTransactionId; + } + + public void setGameStateChangeTransactionId(final short gameStateChangeTransactionId) { + this.gameStateChangeTransactionId = gameStateChangeTransactionId; + } + + public void setPositionPingId(final short positionPingId) { + this.positionPingId = positionPingId; + } + + public void setEntityEffectPingId(final short entityEffectPingId) { + this.entityEffectPingId = entityEffectPingId; + } + + public void setRemoveEntityEffectPingId(final short removeEntityEffectPingId) { + this.removeEntityEffectPingId = removeEntityEffectPingId; + } + + public void setGameStateChangePingId(final short gameStateChangePingId) { + this.gameStateChangePingId = gameStateChangePingId; + } + + public void setHelmet(final ItemStack helmet) { + this.helmet = helmet; + } + + public void setChestplate(final ItemStack chestplate) { + this.chestplate = chestplate; + } + + public void setLeggings(final ItemStack leggings) { + this.leggings = leggings; + } + + public void setBoots(final ItemStack boots) { + this.boots = boots; + } + + public void setItemInMainHand(final ItemStack itemInMainHand) { + this.itemInMainHand = itemInMainHand; + } + + public void setItemInOffHand(final ItemStack itemInOffHand) { + this.itemInOffHand = itemInOffHand; + } + + public void setBerserking(final boolean berserking) { + this.berserking = berserking; + } + + static { + GENERIC_MOVEMENT_SPEED = (ServerUtil.isHigherThan1_16() ? "attribute.name.generic.movement_speed" : "generic.movementSpeed"); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/data/processor/ClickProcessor.java b/src/main/java/me/frep/vulcan/spigot/data/processor/ClickProcessor.java new file mode 100644 index 0000000..ae35d20 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/data/processor/ClickProcessor.java @@ -0,0 +1,87 @@ +package me.frep.vulcan.spigot.data.processor; + +import java.util.Collection; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.util.type.EvictingList; +import me.frep.vulcan.spigot.data.PlayerData; + +public class ClickProcessor +{ + private final PlayerData data; + private long lastSwing; + private long delay; + private long lastInteractEntity; + private final EvictingList samples; + private double cps; + private double kurtosis; + + public ClickProcessor(final PlayerData data) { + this.lastSwing = -1L; + this.lastInteractEntity = System.currentTimeMillis(); + this.samples = new EvictingList(20); + this.data = data; + } + + public void handleArmAnimation() { + if (!this.data.getExemptProcessor().isExempt(ExemptType.AUTOCLICKER_NON_DIG)) { + final long now = System.currentTimeMillis(); + if (this.lastSwing > 0L) { + this.delay = now - this.lastSwing; + this.samples.add(this.delay); + if (this.samples.isFull()) { + this.cps = MathUtil.getCps(this.samples); + } + } + this.lastSwing = now; + } + } + + public PlayerData getData() { + return this.data; + } + + public long getLastSwing() { + return this.lastSwing; + } + + public long getDelay() { + return this.delay; + } + + public long getLastInteractEntity() { + return this.lastInteractEntity; + } + + public EvictingList getSamples() { + return this.samples; + } + + public double getCps() { + return this.cps; + } + + public double getKurtosis() { + return this.kurtosis; + } + + public void setLastSwing(final long lastSwing) { + this.lastSwing = lastSwing; + } + + public void setDelay(final long delay) { + this.delay = delay; + } + + public void setLastInteractEntity(final long lastInteractEntity) { + this.lastInteractEntity = lastInteractEntity; + } + + public void setCps(final double cps) { + this.cps = cps; + } + + public void setKurtosis(final double kurtosis) { + this.kurtosis = kurtosis; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/data/processor/CombatProcessor.java b/src/main/java/me/frep/vulcan/spigot/data/processor/CombatProcessor.java new file mode 100644 index 0000000..5e10494 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/data/processor/CombatProcessor.java @@ -0,0 +1,152 @@ +package me.frep.vulcan.spigot.data.processor; + +import org.bukkit.util.Vector; +import me.frep.vulcan.spigot.util.MathUtil; +import org.bukkit.World; +import io.github.retrooper.packetevents.packetwrappers.play.out.entity.WrappedPacketOutEntity; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.entity.ItemFrame; +import io.github.retrooper.packetevents.packetwrappers.play.in.useentity.WrappedPacketInUseEntity; +import org.bukkit.Location; +import me.frep.vulcan.spigot.util.type.Pair; +import me.frep.vulcan.spigot.util.type.EvictingList; +import org.bukkit.entity.Player; +import org.bukkit.entity.Entity; +import me.frep.vulcan.spigot.data.PlayerData; + +public class CombatProcessor +{ + private final PlayerData data; + private int hitTicks; + private int lastTargetAttackTick; + private int lastPlayerAttackDamage; + private int lastItemFrame; + private Entity target; + private Player trackedPlayer; + private Player lastTrackedPlayer; + private double distance; + private double complexDistance; + private final EvictingList> targetLocations; + + public CombatProcessor(final PlayerData data) { + this.hitTicks = 100; + this.targetLocations = new EvictingList>(20); + this.data = data; + } + + public void handleUseEntity(final WrappedPacketInUseEntity wrapper) { + if (wrapper.getEntity() instanceof ItemFrame) { + this.lastItemFrame = Vulcan.INSTANCE.getTickManager().getTicks(); + } + if (wrapper.getAction() != WrappedPacketInUseEntity.EntityUseAction.ATTACK) { + return; + } + this.target = wrapper.getEntity(); + if (this.target != null) { + this.distance = this.data.getPlayer().getLocation().toVector().setY(0).distance(this.target.getLocation().toVector().setY(0)) - 0.42; + } + if (wrapper.getEntity() instanceof Player) { + this.lastTrackedPlayer = (Player)((this.trackedPlayer == null) ? wrapper.getEntity() : this.trackedPlayer); + this.trackedPlayer = (Player)wrapper.getEntity(); + if (this.trackedPlayer != this.lastTrackedPlayer) { + this.targetLocations.clear(); + } + } + this.hitTicks = 0; + } + + public void handleRelEntityMove(final WrappedPacketOutEntity wrapper) { + if (this.trackedPlayer != null && this.trackedPlayer.getEntityId() == wrapper.getEntityId()) { + final PlayerData targetData = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(this.trackedPlayer); + if (targetData == null) { + return; + } + final int ticks = Vulcan.INSTANCE.getTickManager().getTicks(); + final World world = targetData.getPlayer().getWorld(); + final double x = targetData.getPositionProcessor().getX() - wrapper.getDeltaX(); + final double y = targetData.getPositionProcessor().getY() - wrapper.getDeltaY(); + final double z = targetData.getPositionProcessor().getZ() - wrapper.getDeltaZ(); + final Location targetLocation = new Location(world, x, y, z); + this.targetLocations.add(new Pair(targetLocation, ticks)); + } + } + + public void handleServerPosition() { + this.targetLocations.clear(); + } + + public void handleBukkitAttack() { + this.lastTargetAttackTick = Vulcan.INSTANCE.getTickManager().getTicks(); + } + + public void handleBukkitAttackDamage() { + this.lastPlayerAttackDamage = Vulcan.INSTANCE.getTickManager().getTicks(); + } + + public int getTicksSinceAttack() { + return Vulcan.INSTANCE.getTickManager().getTicks() - this.lastTargetAttackTick; + } + + public int getTicksSinceAttackDamage() { + return Vulcan.INSTANCE.getTickManager().getTicks() - this.lastPlayerAttackDamage; + } + + public void handleFlying() { + ++this.hitTicks; + if (!this.targetLocations.isEmpty() && this.trackedPlayer != null) { + final int ticks = Vulcan.INSTANCE.getTickManager().getTicks(); + final int pingTicks = MathUtil.getPingInTicks(this.data); + final double x = this.data.getPositionProcessor().getX(); + final double z = this.data.getPositionProcessor().getZ(); + final Vector origin = new Vector(x, 0.0, z); + this.complexDistance = this.data.getCombatProcessor().getTargetLocations().stream().filter(pair -> Math.abs(ticks - pair.getY() - pingTicks) < 3).mapToDouble(pair -> { + final Vector victimVector = pair.getX().toVector().setY(0); + return origin.distance(victimVector) - 0.52; + }).min().orElse(-1.0); + } + } + + public PlayerData getData() { + return this.data; + } + + public int getHitTicks() { + return this.hitTicks; + } + + public int getLastTargetAttackTick() { + return this.lastTargetAttackTick; + } + + public int getLastPlayerAttackDamage() { + return this.lastPlayerAttackDamage; + } + + public int getLastItemFrame() { + return this.lastItemFrame; + } + + public Entity getTarget() { + return this.target; + } + + public Player getTrackedPlayer() { + return this.trackedPlayer; + } + + public Player getLastTrackedPlayer() { + return this.lastTrackedPlayer; + } + + public double getDistance() { + return this.distance; + } + + public double getComplexDistance() { + return this.complexDistance; + } + + public EvictingList> getTargetLocations() { + return this.targetLocations; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/data/processor/ConnectionProcessor.java b/src/main/java/me/frep/vulcan/spigot/data/processor/ConnectionProcessor.java new file mode 100644 index 0000000..d6431d6 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/data/processor/ConnectionProcessor.java @@ -0,0 +1,282 @@ +package me.frep.vulcan.spigot.data.processor; + +import me.frep.vulcan.spigot.util.ServerUtil; +import org.bukkit.plugin.Plugin; +import me.frep.vulcan.spigot.util.ColorUtil; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.Bukkit; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.config.Config; +import io.github.retrooper.packetevents.packetwrappers.play.in.pong.WrappedPacketInPong; +import io.github.retrooper.packetevents.packetwrappers.play.in.transaction.WrappedPacketInTransaction; +import me.frep.vulcan.spigot.util.PlayerUtil; +import java.util.HashMap; +import java.util.Map; +import me.frep.vulcan.spigot.data.PlayerData; + +public class ConnectionProcessor +{ + private final PlayerData data; + private int keepAlivePing; + private int pingId; + private int flightDesyncTicks; + private short transactionId; + private final Map transactionQueue; + private final Map pingQueue; + private long lastFlying; + private long flyingDelay; + private long lastRepliedTransaction; + private long transactionPing; + private long lastKeepAlive; + private long lastFast; + private boolean fast; + private double transactionBuffer; + private double keepAliveBuffer; + private boolean transactionKicked; + private boolean keepAliveKicked; + private int maxPingBuffer; + private boolean maxPingKicked; + + public ConnectionProcessor(final PlayerData data) { + this.pingId = -25768; + this.flightDesyncTicks = 0; + this.transactionId = -25768; + this.transactionQueue = new HashMap(); + this.pingQueue = new HashMap(); + this.lastRepliedTransaction = System.currentTimeMillis(); + this.lastKeepAlive = System.currentTimeMillis(); + this.lastFast = System.currentTimeMillis(); + this.data = data; + } + + public void handleFlying() { + final long now = System.currentTimeMillis(); + this.flyingDelay = now - this.lastFlying; + this.fast = (this.flyingDelay <= 3L); + if (this.fast) { + this.lastFast = System.currentTimeMillis(); + } + this.keepAlivePing = PlayerUtil.getPing(this.data.getPlayer()); + this.lastFlying = now; + this.confirmTransactionConnection(); + this.confirmKeepAliveConnection(); + this.handleFlightDesync(); + this.handleMaxPingKick(); + } + + public void handleKeepAlive() { + this.lastKeepAlive = System.currentTimeMillis(); + } + + public void sendPing() { + ++this.pingId; + if (this.pingId > -24769) { + this.pingId = -25768; + } + this.data.setPendingTransactions(this.data.getPendingTransactions() + 1); + this.data.sendPing(this.pingId); + this.pingQueue.put(this.pingId, System.currentTimeMillis()); + } + + public void sendTransaction() { + ++this.transactionId; + if (this.transactionId > -24769) { + this.transactionId = -25768; + } + this.data.setPendingTransactions(this.data.getPendingTransactions() + 1); + this.data.sendTransaction(this.transactionId); + this.transactionQueue.put(this.transactionId, System.currentTimeMillis()); + } + + public void handleTransaction(final WrappedPacketInTransaction wrapper) { + if (this.transactionQueue.containsKey(wrapper.getActionNumber())) { + final long sent = this.transactionQueue.get(wrapper.getActionNumber()); + this.lastRepliedTransaction = System.currentTimeMillis(); + this.transactionPing = System.currentTimeMillis() - sent; + this.data.setPendingTransactions(this.data.getPendingTransactions() - 1); + this.transactionQueue.remove(wrapper.getActionNumber()); + } + } + + public void handlePong(final WrappedPacketInPong wrapper) { + if (this.pingQueue.containsKey(wrapper.getId())) { + final long sent = this.pingQueue.get(wrapper.getId()); + this.lastRepliedTransaction = System.currentTimeMillis(); + this.transactionPing = System.currentTimeMillis() - sent; + this.data.setPendingTransactions(this.data.getPendingTransactions() - 1); + this.pingQueue.remove(wrapper.getId()); + } + } + + public void handleFlightDesync() { + if (!Config.DESYNC_KICK_ENABLED) { + return; + } + final boolean confirmed = this.data.getPositionProcessor().isAllowFlight(); + final boolean unconfirmed = this.data.getPlayer().getAllowFlight(); + final boolean joined = this.data.getExemptProcessor().isExempt(ExemptType.JOINED); + if (confirmed && !unconfirmed && !joined) { + if (++this.flightDesyncTicks > Config.DESYNC_MAX_TICKS) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().kickPlayer(ColorUtil.translate(Config.DESYNC_KICK_MESSAGE))); + if (!Config.DESYNC_STAFF_KICK_MESSAGE.equals("")) { + Vulcan.INSTANCE.getAlertManager().sendMessage(Config.DESYNC_STAFF_KICK_MESSAGE.replaceAll("%ticks%", Integer.toString(this.flightDesyncTicks)).replaceAll("%player%", this.data.getPlayer().getName())); + } + if (!Config.DESYNC_CONSOLE_MESSAGE.equals("")) { + ServerUtil.log(ColorUtil.translate(Config.DESYNC_CONSOLE_MESSAGE.replaceAll("%player%", this.data.getPlayer().getName()).replaceAll("%ticks%", Integer.toString(this.flightDesyncTicks)))); + } + } + } + else if (this.flightDesyncTicks > 0) { + this.flightDesyncTicks -= (int)0.05; + } + } + + private void confirmTransactionConnection() { + if (!Config.TRANSACTION_KICK_ENABLED || this.data.getPlayer().hasPermission("vulcan.bypass.connection.transaction")) { + return; + } + final long delay = System.currentTimeMillis() - this.lastRepliedTransaction; + if (delay > Config.TRANSACTION_MAX_DELAY && !this.transactionKicked) { + final double transactionBuffer = this.transactionBuffer + 1.0; + this.transactionBuffer = transactionBuffer; + if (transactionBuffer > 5.0) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().kickPlayer(ColorUtil.translate(Config.TRANSACTION_KICK_MESSAGE))); + if (!Config.TRANSACTION_STAFF_ALERT_MESSAGE.equals("")) { + Vulcan.INSTANCE.getAlertManager().sendMessage(Config.TRANSACTION_STAFF_ALERT_MESSAGE.replaceAll("%delay%", Long.toString(delay)).replaceAll("%player%", this.data.getPlayer().getName())); + } + if (!Config.TRANSACTION_KICK_CONSOLE_MESSAGE.equals("")) { + ServerUtil.log(ColorUtil.translate(Config.TRANSACTION_KICK_CONSOLE_MESSAGE.replaceAll("%player%", this.data.getPlayer().getName()).replaceAll("%delay%", Long.toString(delay)))); + } + this.transactionKicked = true; + } + else if (this.transactionBuffer > 0.0) { + this.transactionBuffer -= 0.1; + } + } + } + + private void confirmKeepAliveConnection() { + if (!Config.KEEPALIVE_KICK_ENABLED || this.data.getPlayer().hasPermission("vulcan.bypass.connection.keepalive")) { + return; + } + final long delay = System.currentTimeMillis() - this.lastKeepAlive; + if (delay > Config.KEEPALIVE_MAX_DELAY && !this.keepAliveKicked) { + final double keepAliveBuffer = this.keepAliveBuffer + 1.0; + this.keepAliveBuffer = keepAliveBuffer; + if (keepAliveBuffer > 5.0) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().kickPlayer(ColorUtil.translate(Config.TRANSACTION_KICK_MESSAGE))); + if (!Config.KEEPALIVE_STAFF_ALERT_MESSAGE.equals("")) { + Vulcan.INSTANCE.getAlertManager().sendMessage(Config.KEEPALIVE_STAFF_ALERT_MESSAGE.replaceAll("%delay%", Long.toString(delay)).replaceAll("%player%", this.data.getPlayer().getName())); + } + if (!Config.KEEPALIVE_KICK_CONSOLE_MESSAGE.equals("")) { + ServerUtil.log(ColorUtil.translate(Config.KEEPALIVE_KICK_CONSOLE_MESSAGE.replaceAll("%player%", this.data.getPlayer().getName()).replaceAll("%delay%", Long.toString(delay)))); + } + this.keepAliveKicked = true; + } + else if (this.keepAliveBuffer > 0.0) { + this.keepAliveBuffer -= 0.1; + } + } + } + + private void handleMaxPingKick() { + if (!Config.MAX_PING_KICK_ENABLED || this.data.getPlayer().hasPermission("vulcan.bypass.connection.max-ping")) { + return; + } + if (this.keepAlivePing > Config.MAX_PING && !this.maxPingKicked) { + if (++this.maxPingBuffer > Config.MAX_PING_KICK_TICKS) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().kickPlayer(ColorUtil.translate(Config.MAX_PING_KICK_MESSAGE))); + if (!Config.MAX_PING_KICK_STAFF_ALERT_MESSAGE.equals("")) { + Vulcan.INSTANCE.getAlertManager().sendMessage(Config.MAX_PING_KICK_STAFF_ALERT_MESSAGE.replaceAll("%ping%", Long.toString(this.keepAlivePing)).replaceAll("%player%", this.data.getPlayer().getName())); + } + if (!Config.MAX_PING_KICK_CONSOLE_MESSAGE.equals("")) { + ServerUtil.log(ColorUtil.translate(Config.MAX_PING_KICK_CONSOLE_MESSAGE.replaceAll("%player%", this.data.getPlayer().getName()).replaceAll("%ping%", Long.toString(this.keepAlivePing)))); + } + this.maxPingKicked = true; + } + } + else if (this.maxPingBuffer > 0) { + --this.maxPingBuffer; + } + } + + public PlayerData getData() { + return this.data; + } + + public int getKeepAlivePing() { + return this.keepAlivePing; + } + + public int getPingId() { + return this.pingId; + } + + public int getFlightDesyncTicks() { + return this.flightDesyncTicks; + } + + public short getTransactionId() { + return this.transactionId; + } + + public Map getTransactionQueue() { + return this.transactionQueue; + } + + public Map getPingQueue() { + return this.pingQueue; + } + + public long getLastFlying() { + return this.lastFlying; + } + + public long getFlyingDelay() { + return this.flyingDelay; + } + + public long getLastRepliedTransaction() { + return this.lastRepliedTransaction; + } + + public long getTransactionPing() { + return this.transactionPing; + } + + public long getLastKeepAlive() { + return this.lastKeepAlive; + } + + public long getLastFast() { + return this.lastFast; + } + + public boolean isFast() { + return this.fast; + } + + public double getTransactionBuffer() { + return this.transactionBuffer; + } + + public double getKeepAliveBuffer() { + return this.keepAliveBuffer; + } + + public boolean isTransactionKicked() { + return this.transactionKicked; + } + + public boolean isKeepAliveKicked() { + return this.keepAliveKicked; + } + + public int getMaxPingBuffer() { + return this.maxPingBuffer; + } + + public boolean isMaxPingKicked() { + return this.maxPingKicked; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/data/processor/PositionProcessor.java b/src/main/java/me/frep/vulcan/spigot/data/processor/PositionProcessor.java new file mode 100644 index 0000000..7bcfe70 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/data/processor/PositionProcessor.java @@ -0,0 +1,3474 @@ +package me.frep.vulcan.spigot.data.processor; + +import io.github.retrooper.packetevents.packetwrappers.play.in.pong.WrappedPacketInPong; +import io.github.retrooper.packetevents.packetwrappers.play.in.transaction.WrappedPacketInTransaction; +import java.util.logging.Level; +import me.frep.vulcan.spigot.util.ColorUtil; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.plugin.Plugin; +import io.github.retrooper.packetevents.packetwrappers.api.SendableWrapper; +import io.github.retrooper.packetevents.packetwrappers.play.out.blockchange.WrappedPacketOutBlockChange; +import org.bukkit.event.Event; +import org.bukkit.Bukkit; +import me.frep.vulcan.api.event.VulcanGhostBlockEvent; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.WeatherType; +import io.github.retrooper.packetevents.packetwrappers.play.in.blockdig.WrappedPacketInBlockDig; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.GameMode; +import org.bukkit.entity.Boat; +import io.github.retrooper.packetevents.packetwrappers.play.in.vehiclemove.WrappedPacketInVehicleMove; +import org.bukkit.entity.TNTPrimed; +import java.util.Iterator; +import org.bukkit.entity.EnderDragonPart; +import org.bukkit.entity.EnderDragon; +import org.bukkit.entity.Firework; +import org.bukkit.entity.LivingEntity; +import me.frep.vulcan.spigot.util.EntityUtil; +import java.util.Collection; +import me.frep.vulcan.spigot.util.StreamUtil; +import me.frep.vulcan.spigot.util.PlayerUtil; +import org.bukkit.util.NumberConversions; +import me.frep.vulcan.spigot.exempt.ExemptProcessor; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import org.bukkit.WorldBorder; +import java.util.Arrays; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.util.BlockUtil; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.util.MathUtil; +import io.github.retrooper.packetevents.packetwrappers.play.in.flying.WrappedPacketInFlying; +import java.util.HashMap; +import org.bukkit.World; +import org.bukkit.Material; +import org.bukkit.entity.Entity; +import java.util.List; +import io.github.retrooper.packetevents.packetwrappers.play.out.abilities.WrappedPacketOutAbilities; +import java.util.Map; +import org.bukkit.Location; +import me.frep.vulcan.spigot.data.PlayerData; + +public class PositionProcessor +{ + private final PlayerData data; + private boolean nearFence; + private boolean nearLiquid; + private boolean nearSlime; + private boolean nearSoulSand; + private boolean nearClimbable; + private boolean nearWeb; + private boolean nearLilyPad; + private boolean nearDaylightSensor; + private boolean nearBrewingStand; + private boolean nearWall; + private boolean nearStair; + private boolean nearSlab; + private boolean nearHoney; + private boolean nearScaffolding; + private boolean nearTrapdoor; + private boolean nearSkull; + private boolean nearPortalFrame; + private boolean nearCampfire; + private boolean nearSweetBerries; + private boolean nearShulkerBox; + private boolean vehicleNearBubbleColumn; + private boolean nearSnow; + private boolean nearAnvil; + private boolean nearEndRod; + private boolean nearChain; + private boolean nearPiston; + private boolean nearDoor; + private boolean touchingAir; + private boolean nearCauldron; + private boolean nearLava; + private boolean nearHopper; + private boolean nearFenceGate; + private boolean nearFlowerPot; + private boolean onClimbable; + private boolean inWeb; + private boolean inBubbleColumn; + private boolean fullySubmerged; + private boolean inLiquid; + private boolean collidingVertically; + private boolean nearKelp; + private boolean fullyStuck; + private boolean partiallyStuck; + private boolean onIce; + private boolean clientOnGround; + private boolean mathematicallyOnGround; + private boolean nearShulker; + private boolean nearBoat; + private boolean nearBell; + private boolean nearBed; + private boolean nearCarpet; + private boolean nearLectern; + private boolean nearTurtleEgg; + private boolean nearSeaPickle; + private boolean nearIce; + private boolean nearConduit; + private boolean collidingHorizontally; + private boolean nearRepeater; + private boolean nearSolid; + private boolean nearPane; + private boolean vehicleNearIce; + private boolean vehicleNearLiquid; + private boolean vehicleNearSlime; + private boolean vehicleInAir; + private boolean moving; + private boolean nearFrostedIce; + private boolean nearBubbleColumn; + private boolean nearFarmland; + private boolean lastClientOnGround; + private boolean allowFlight; + private boolean nearSeaGrass; + private boolean nearChest; + private boolean vehicleNearPiston; + private boolean nearCake; + private boolean vehicleNearBed; + private boolean nearAmethyst; + private boolean nearDripstone; + private boolean nearPowderSnow; + private boolean setbackGround; + private boolean collidingEntity; + private boolean lastLastClientOnGround; + private boolean vehicleNearEntity; + private boolean nearPath; + private boolean nearLantern; + private boolean nearBorder; + private boolean nearRail; + private boolean nearSign; + private boolean nearBamboo; + private boolean nearPressurePlate; + private boolean fuckedPosition; + private boolean nearEnchantmentTable; + private Location from; + private Location to; + private short abilitiesTransactionId; + private short abilitiesPingId; + private final Map queuedAbilities; + public boolean frozen; + public List nearbyEntities; + private Material blockBelow; + private Material blockBelow2; + private Material blockBelow3; + private List nearbyBlocks; + private List blocksBelow; + private List blocksAbove; + private List blocksAround; + private List glitchedBlocksAbove; + public List nearbyBlocksModern; + public List vehicleBlocks; + public List blocksUnderModern; + public Material blockBelowModern; + public Material blockBelow2Modern; + public Material blockBelow3Modern; + private double x; + private double y; + private double z; + private double lastX; + private double lastY; + private double lastZ; + private double deltaX; + private double deltaY; + private double deltaZ; + private double deltaXZ; + private double deltaXYZ; + private double lastDeltaX; + private double lastDeltaZ; + private double lastDeltaY; + private double lastDeltaXZ; + private double vehicleX; + private double vehicleY; + private double vehicleZ; + private double lastVehicleX; + private double lastVehicleY; + private double lastVehicleZ; + private double lastVehicleDeltaX; + private double lastVehicleDeltaY; + private double lastVehicleDeltaZ; + private double vehicleDeltaX; + private double vehicleDeltaY; + private double vehicleDeltaZ; + private double vehicleDeltaXZ; + private double lastOnGroundX; + private double lastOnGroundY; + private double lastOnGroundZ; + private double setbackX; + private double setbackY; + private double setbackZ; + private double ghostBlockBuffer; + private double newSetbackX; + private double newSetbackY; + private double newSetbackZ; + private double ghostBlockSetbackX; + private double ghostBlockSetbackY; + private double ghostBlockSetbackZ; + private double lastLegitX; + private double lastLegitY; + private double lastLegitZ; + private double lastLastX; + private double lastLastY; + private double lastLastZ; + private double firstJoinX; + private double firstJoinY; + private double firstJoinZ; + private double unloadedChunkBuffer; + private int sinceVehicleTicks; + private int sinceFlyingTicks; + private int sinceTrapdoorTicks; + private int clientAirTicks; + private int clientGroundTicks; + private int sinceSwimmingTicks; + private int sinceRiptideTicks; + private int sinceGlidingTicks; + private int sinceIceTicks; + private int sinceDolphinsGraceTicks; + private int sinceLevitationTicks; + private int sinceBubbleColumnTicks; + private int glidingTicks; + private int sinceSlowFallingTicks; + private int serverAirTicks; + private int serverGroundTicks; + private int sinceWebTicks; + private int sinceLiquidTicks; + private int climbableTicks; + private int sinceJumpBoostTicks; + private int sinceNearSlimeTicks; + private int sinceHoneyTicks; + private int sinceCollidingVerticallyTicks; + private int sinceNearFenceTicks; + private int sinceSoulSpeedTicks; + private int sinceNearBedTicks; + private int lastPulledByFishingRod; + private int vehicleTicks; + private int sinceFireworkTicks; + private int sinceNearIceTicks; + private int sinceNearPistonTicks; + private int lastWaterLogged; + private int sinceSpeedTicks; + private int lastAttributeModifier; + private int sinceAroundSlimeTicks; + private int sinceAroundPistonTicks; + private int sinceVehicleNearIceTicks; + private int sinceVehicleNearLiquidTicks; + private int sinceVehicleNearSlimeTicks; + private int sinceVehicleNearBubbleColumnTicks; + private int blockX; + private int blockY; + private int blockZ; + private int sinceNearFrostedIceTicks; + private int sinceNearScaffoldingTicks; + private int ticksSinceGhostBlockSetback; + private int lastServerAbilities; + private int vehicleAirTicks; + private int sinceNearShulkerBoxTicks; + private int sinceElytraTicks; + private int lastGhostBlockSetback; + private int sinceNearFarmlandTicks; + private int sinceNearStairTicks; + private int sinceNearSlabTicks; + private int sinceEntityCollisionTicks; + private int sinceVehicleNearPistonTicks; + private int sinceFishingRodTicks; + private int sinceAttributeModifierTicks; + private int sinceHighFlySpeedTicks; + private int sinceAroundSlabTicks; + private int sinceVehicleNearBedTicks; + private int sinceWaterLogTicks; + private int sinceGroundSpeedFailTicks; + private int sinceNearClimbableTicks; + private int boatsAround; + private int sinceSetbackTicks; + private int sinceCollidingHorizontallyTicks; + private int sinceFlagTicks; + private int sinceFuckingEntityTicks; + private int sinceSpectatorTicks; + private World world; + private Entity bukkitVehicle; + private Entity lastBukkitVehicle; + private float moveForward; + private float moveStrafing; + private float walkSpeed; + private float flySpeed; + private boolean exemptFlight; + private boolean exemptCreative; + private boolean exemptJoined; + private boolean exemptLiquid; + private boolean exemptLevitation; + private boolean exemptSlowFalling; + private boolean exemptRiptide; + private boolean exemptVehicle; + private boolean exemptLenientScaffolding; + private boolean exemptBukkitVelocity; + private boolean exemptGliding; + private boolean exemptElytra; + private boolean exemptTeleport; + private boolean exemptEnderPearl; + private boolean exemptChunk; + private boolean exemptComboMode; + private boolean exemptMythicMob; + private boolean exemptClimbable; + + public PositionProcessor(final PlayerData data) { + this.abilitiesTransactionId = -30768; + this.abilitiesPingId = -30768; + this.queuedAbilities = new HashMap(); + this.sinceVehicleTicks = 100; + this.sinceFlyingTicks = 100; + this.sinceTrapdoorTicks = 100; + this.sinceSwimmingTicks = 100; + this.sinceRiptideTicks = 200; + this.sinceGlidingTicks = 100; + this.sinceDolphinsGraceTicks = 100; + this.sinceLevitationTicks = 100; + this.sinceBubbleColumnTicks = 100; + this.sinceSlowFallingTicks = 100; + this.sinceWebTicks = 100; + this.sinceLiquidTicks = 100; + this.sinceJumpBoostTicks = 100; + this.sinceNearSlimeTicks = 100; + this.sinceHoneyTicks = 100; + this.sinceCollidingVerticallyTicks = 100; + this.sinceNearFenceTicks = 100; + this.sinceSoulSpeedTicks = 100; + this.sinceNearBedTicks = 100; + this.sinceFireworkTicks = 200; + this.sinceNearIceTicks = 100; + this.sinceNearPistonTicks = 100; + this.sinceSpeedTicks = 100; + this.sinceAroundSlimeTicks = 500; + this.sinceAroundPistonTicks = 500; + this.sinceVehicleNearIceTicks = 500; + this.sinceVehicleNearLiquidTicks = 150; + this.sinceVehicleNearSlimeTicks = 150; + this.sinceVehicleNearBubbleColumnTicks = 150; + this.sinceNearScaffoldingTicks = 100; + this.ticksSinceGhostBlockSetback = 500; + this.sinceNearShulkerBoxTicks = 100; + this.sinceElytraTicks = 100; + this.sinceNearFarmlandTicks = 100; + this.sinceEntityCollisionTicks = 100; + this.sinceVehicleNearPistonTicks = 100; + this.sinceFishingRodTicks = 1000; + this.sinceAttributeModifierTicks = 100; + this.sinceHighFlySpeedTicks = 200; + this.sinceAroundSlabTicks = 100; + this.sinceVehicleNearBedTicks = 1000; + this.sinceWaterLogTicks = 1000; + this.sinceGroundSpeedFailTicks = 1000; + this.sinceNearClimbableTicks = 1000; + this.boatsAround = 0; + this.sinceSetbackTicks = 1000; + this.sinceCollidingHorizontallyTicks = 100; + this.sinceFlagTicks = 1000; + this.sinceFuckingEntityTicks = 100; + this.sinceSpectatorTicks = 100; + this.moveForward = 0.0f; + this.moveStrafing = 0.0f; + this.walkSpeed = 0.2f; + this.flySpeed = 0.2f; + this.data = data; + } + + public void onJoin() { + this.walkSpeed = this.data.getPlayer().getWalkSpeed(); + final Location location = this.data.getPlayer().getLocation(); + this.firstJoinX = location.getX(); + this.firstJoinY = location.getY(); + this.firstJoinZ = location.getZ(); + this.setbackX = location.getX(); + this.setbackY = location.getY(); + this.setbackZ = location.getZ(); + } + + public void handleFlying(final WrappedPacketInFlying wrapper) { + this.lastLastClientOnGround = this.lastClientOnGround; + this.lastClientOnGround = this.clientOnGround; + this.clientOnGround = wrapper.isOnGround(); + this.handleFlyingTicks(); + if (wrapper.isPosition()) { + this.fuckedPosition = (this.blockX == 0 && this.blockY == 0 && this.blockZ == 0); + this.world = this.data.getPlayer().getWorld(); + this.lastLastX = this.lastX; + this.lastLastY = this.lastY; + this.lastLastZ = this.lastZ; + this.lastX = this.x; + this.lastY = this.y; + this.lastZ = this.z; + this.x = wrapper.getX(); + this.y = wrapper.getY(); + this.z = wrapper.getZ(); + this.from = ((this.to == null) ? new Location(this.world, this.x, this.y, this.z) : this.to); + this.to = new Location(this.world, this.x, this.y, this.z); + this.lastDeltaX = this.deltaX; + this.lastDeltaY = this.deltaY; + this.lastDeltaZ = this.deltaZ; + this.lastDeltaXZ = this.deltaXZ; + this.deltaX = this.x - this.lastX; + this.deltaY = this.y - this.lastY; + this.deltaZ = this.z - this.lastZ; + this.deltaXZ = MathUtil.hypot(this.deltaX, this.deltaZ); + this.deltaXYZ = MathUtil.magnitude(this.deltaX, this.deltaY, this.deltaZ); + this.moving = (Math.abs(this.deltaX) > 0.0 || Math.abs(this.deltaZ) > 0.0 || Math.abs(this.deltaY) > 0.0); + this.mathematicallyOnGround = (this.y % 0.015625 == 0.0); + if (this.data.getPlayer().getVehicle() == null) { + this.vehicleTicks = 0; + } + if (ServerUtil.isHigherThan1_13()) { + this.cacheBlocksModern(); + } + else { + this.cacheBlocksLegacy(); + } + this.handleGhostBlock(); + this.handleUnloadedChunk(); + if (ServerUtil.isHigherThan1_13() && !this.frozen) { + if (this.blockBelowModern != null && this.blockBelowModern != Material.AIR && this.blockBelowModern.isBlock() && this.mathematicallyOnGround && !BlockUtil.isLiquid(this.blockBelowModern) && this.sinceSetbackTicks > 5 && this.deltaXZ < 2.0 && !this.data.getActionProcessor().isTeleporting() && this.ticksSinceGhostBlockSetback > 10) { + this.setbackX = this.x; + this.setbackY = this.y; + this.setbackZ = this.z; + } + } + else if (this.blockBelow != null && this.blockBelow.isSolid() && this.mathematicallyOnGround && !BlockUtil.isLiquid(this.blockBelow) && !this.frozen && this.deltaXZ < 2.0 && this.sinceSetbackTicks > 5 && !this.data.getActionProcessor().isTeleporting() && this.ticksSinceGhostBlockSetback > 10) { + this.setbackX = this.x; + this.setbackY = this.y; + this.setbackZ = this.z; + } + this.handlePositionTicks(); + this.parseForwardAndStrafe(); + if (this.data.getActionProcessor().getGenericMovementSpeed() > 0.11) { + this.sinceAttributeModifierTicks = 0; + } + this.cacheExemptions(); + if (Config.VELOCITY_WORLD_BORDER && ServerUtil.isHigherThan1_8()) { + final WorldBorder worldBorder = this.world.getWorldBorder(); + final double centerX = worldBorder.getCenter().getX(); + final double centerZ = worldBorder.getCenter().getZ(); + final double size = worldBorder.getSize() / 2.0; + double dx1 = this.x - centerX - size; + double dx2 = this.x - centerX + size; + double dx3 = this.z - centerZ - size; + double dx4 = this.z - centerZ + size; + if (dx1 < 0.0) { + dx1 *= -1.0; + } + if (dx2 < 0.0) { + dx2 *= -1.0; + } + if (dx3 < 0.0) { + dx3 *= -1.0; + } + if (dx4 < 0.0) { + dx4 *= -1.0; + } + final double[] distances = { dx1, dx2, dx3, dx4 }; + Arrays.sort(distances); + this.nearBorder = (distances[0] < 1.0); + } + } + } + + private void cacheExemptions() { + final ExemptProcessor exemptProcessor = this.data.getExemptProcessor(); + this.exemptFlight = exemptProcessor.isExempt(ExemptType.FLIGHT); + this.exemptCreative = exemptProcessor.isExempt(ExemptType.CREATIVE); + this.exemptJoined = exemptProcessor.isExempt(ExemptType.JOINED); + this.exemptLiquid = exemptProcessor.isExempt(ExemptType.LIQUID); + this.exemptLevitation = exemptProcessor.isExempt(ExemptType.LEVITATION); + this.exemptSlowFalling = exemptProcessor.isExempt(ExemptType.SLOW_FALLING); + this.exemptRiptide = exemptProcessor.isExempt(ExemptType.RIPTIDE); + this.exemptVehicle = exemptProcessor.isExempt(ExemptType.VEHICLE); + this.exemptLenientScaffolding = exemptProcessor.isExempt(ExemptType.LENIENT_SCAFFOLDING); + this.exemptBukkitVelocity = exemptProcessor.isExempt(ExemptType.BUKKIT_VELOCITY); + this.exemptGliding = exemptProcessor.isExempt(ExemptType.GLIDING); + this.exemptElytra = exemptProcessor.isExempt(ExemptType.ELYTRA); + this.exemptTeleport = exemptProcessor.isExempt(ExemptType.TELEPORT); + this.exemptEnderPearl = exemptProcessor.isExempt(ExemptType.ENDER_PEARL); + this.exemptChunk = exemptProcessor.isExempt(ExemptType.CHUNK); + this.exemptComboMode = exemptProcessor.isExempt(ExemptType.COMBO_MODE); + this.exemptMythicMob = exemptProcessor.isExempt(ExemptType.MYTHIC_MOB); + this.exemptClimbable = exemptProcessor.isExempt(ExemptType.CLIMBABLE); + } + + private void cacheBlocksModern() { + if (this.nearbyBlocksModern == null || this.blockBelowModern == null || this.blockBelow2Modern == null || this.blockBelow3Modern == null) { + return; + } + this.blockX = NumberConversions.floor(this.x); + this.blockY = NumberConversions.floor(this.y); + this.blockZ = NumberConversions.floor(this.z); + this.blocksBelow = PlayerUtil.getBlocksBelowModern(this.data); + this.blocksAbove = PlayerUtil.getBlocksAboveModern(this.data); + this.blocksAround = PlayerUtil.getBlocksAroundModern(this.data); + this.glitchedBlocksAbove = PlayerUtil.getBlocksAboveGlitchedModern(this.data); + this.onIce = PlayerUtil.isOnIceModern(this.data); + this.fullyStuck = PlayerUtil.isFullyStuckModern(this.data); + this.partiallyStuck = PlayerUtil.isFullyStuckModern(this.data); + this.collidingVertically = !StreamUtil.allMatch(this.blocksAbove, BlockUtil::isAir); + this.collidingHorizontally = !StreamUtil.allMatch(this.blocksAround, BlockUtil::isAir); + this.nearSolid = StreamUtil.anyMatch(this.nearbyBlocksModern, BlockUtil::isSolid); + this.touchingAir = (StreamUtil.allMatch(this.blocksAround, BlockUtil::isAir) && StreamUtil.allMatch(this.blocksBelow, BlockUtil::isAir)); + this.handleCollisionsModern(); + } + + private void handleCollisionsModern() { + if (this.nearbyBlocksModern != null && this.nearbyEntities != null) { + final boolean b = false; + this.nearPowderSnow = b; + this.nearDripstone = b; + this.nearCake = b; + this.nearChest = b; + this.nearSeaGrass = b; + this.nearLava = b; + this.nearFarmland = b; + this.nearBubbleColumn = b; + this.nearFrostedIce = b; + this.nearSign = b; + this.nearPressurePlate = b; + this.nearEnchantmentTable = b; + this.nearAmethyst = b; + this.nearHoney = b; + this.nearScaffolding = b; + this.nearChain = b; + this.nearEndRod = b; + this.nearTurtleEgg = b; + this.nearKelp = b; + this.nearShulkerBox = b; + this.nearSeaPickle = b; + this.nearBell = b; + this.nearLectern = b; + this.nearBamboo = b; + this.nearLantern = b; + this.nearConduit = b; + this.nearSweetBerries = b; + this.nearCampfire = b; + this.nearBed = b; + this.nearSkull = b; + this.nearPane = b; + this.nearPiston = b; + this.nearLilyPad = b; + this.nearDoor = b; + this.nearHopper = b; + this.nearSlab = b; + this.nearRail = b; + this.nearRepeater = b; + this.nearAnvil = b; + this.nearSnow = b; + this.nearFenceGate = b; + this.nearIce = b; + this.nearStair = b; + this.nearCauldron = b; + this.nearWall = b; + this.nearBrewingStand = b; + this.nearDaylightSensor = b; + this.nearPath = b; + this.nearPortalFrame = b; + this.nearTrapdoor = b; + this.nearFlowerPot = b; + this.nearWeb = b; + this.nearClimbable = b; + this.nearSoulSand = b; + this.nearCarpet = b; + this.nearLiquid = b; + this.nearFence = b; + this.nearSlime = b; + for (final Material material : this.nearbyBlocksModern) { + this.nearSlime |= (material == Material.SLIME_BLOCK); + this.nearLiquid |= (material == Material.WATER || material == Material.LAVA); + this.nearWeb |= (material == Material.COBWEB); + this.nearFlowerPot |= (material == Material.FLOWER_POT); + this.nearPortalFrame |= (material == Material.END_PORTAL_FRAME); + this.nearDaylightSensor |= (material == Material.DAYLIGHT_DETECTOR); + this.nearBrewingStand |= (material == Material.BREWING_STAND); + this.nearIce |= (material == Material.ICE || material == Material.PACKED_ICE || material == Material.FROSTED_ICE); + this.nearSnow |= (material == Material.SNOW); + this.nearAnvil |= (material == Material.ANVIL || material == Material.CHIPPED_ANVIL || material == Material.DAMAGED_ANVIL); + this.nearRepeater |= (material == Material.REPEATER); + this.nearHopper |= (material == Material.HOPPER); + this.nearLilyPad |= (material == Material.LILY_PAD); + this.nearPiston |= (material == Material.PISTON || material == Material.PISTON_HEAD || material == Material.MOVING_PISTON || material == Material.STICKY_PISTON); + this.nearConduit |= (material == Material.CONDUIT); + this.nearSeaPickle |= (material == Material.SEA_PICKLE); + this.nearKelp |= (material == Material.KELP || material == Material.KELP_PLANT); + this.nearTurtleEgg |= (material == Material.TURTLE_EGG); + this.nearEndRod |= (material == Material.END_ROD); + this.nearScaffolding |= BlockUtil.isScaffolding(material); + this.nearHoney |= BlockUtil.isHoney(material); + this.nearCauldron |= (material == Material.CAULDRON); + this.nearCake |= (material == Material.CAKE); + this.nearEnchantmentTable |= BlockUtil.isEnchantmentTable(material); + this.nearAmethyst |= BlockUtil.isAmethyst(material); + this.nearRail |= BlockUtil.isRail(material); + this.nearLantern |= BlockUtil.isLantern(material); + this.nearPowderSnow |= BlockUtil.isPowderSnow(material); + this.nearDripstone |= BlockUtil.isDripstone(material); + this.nearChest |= BlockUtil.isChest(material); + this.nearSeaGrass |= BlockUtil.isSeaGrass(material); + this.nearBell |= BlockUtil.isBell(material); + this.nearChain |= BlockUtil.isChain(material); + this.nearLectern |= BlockUtil.isLectern(material); + this.nearSweetBerries |= BlockUtil.isSweetBerries(material); + this.nearBubbleColumn |= BlockUtil.isBubbleColumn(material); + this.nearFrostedIce |= BlockUtil.isFrostedIce(material); + this.nearSoulSand |= BlockUtil.isSoulSand(material); + this.nearCarpet |= BlockUtil.isCarpet(material); + this.nearTrapdoor |= BlockUtil.isTrapdoor(material); + this.nearWall |= BlockUtil.isWall(material); + this.nearFarmland |= BlockUtil.isFarmland(material); + this.nearStair |= BlockUtil.isStair(material); + this.nearPressurePlate |= BlockUtil.isPressurePlate(material); + this.nearFence |= BlockUtil.isFence(material); + this.nearClimbable |= BlockUtil.isClimbable(material); + this.nearFenceGate |= BlockUtil.isFenceGate(material); + this.nearSlab |= BlockUtil.isSlab(material); + this.nearDoor |= BlockUtil.isDoor(material); + this.nearPane |= BlockUtil.isPane(material); + this.nearSkull |= BlockUtil.isSkull(material); + this.nearBed |= BlockUtil.isBed(material); + this.nearCampfire |= BlockUtil.isCampfire(material); + this.nearShulkerBox |= BlockUtil.isShulkerBox(material); + this.nearPath |= BlockUtil.isPath(material); + this.nearSign |= BlockUtil.isSign(material); + this.nearBamboo |= BlockUtil.isBamboo(material); + } + final boolean nearBoat = false; + this.collidingEntity = nearBoat; + this.nearShulker = nearBoat; + this.nearBoat = nearBoat; + for (final Entity entity : this.nearbyEntities) { + this.nearBoat |= EntityUtil.isBoat(entity); + this.nearShulker |= EntityUtil.isShulker(entity); + if (entity instanceof LivingEntity) { + this.collidingEntity = true; + } + if (entity instanceof Firework) { + this.sinceFireworkTicks = 0; + } + if (entity instanceof EnderDragon || entity instanceof EnderDragonPart) { + this.data.getActionProcessor().setSinceDragonDamageTicks(0); + } + } + if (this.nearbyEntities.size() > Config.ENTITY_CRAM_FIX_AMOUNT) { + this.sinceFuckingEntityTicks = 0; + } + this.inBubbleColumn = PlayerUtil.isInBubbleColumnModern(this.data); + this.onClimbable = PlayerUtil.isOnClimbableModern(this.data); + this.inWeb = PlayerUtil.isInWebModern(this.data); + this.inLiquid = PlayerUtil.isInLiquidModern(this.data); + this.fullySubmerged = PlayerUtil.isFullySubmergedModern(this.data); + } + if (this.nearBoat || this.nearShulker || this.nearTrapdoor || this.nearCarpet || this.nearCampfire || this.nearBrewingStand || this.nearRepeater || this.nearDaylightSensor || this.nearSkull || this.nearLilyPad || this.nearShulkerBox || this.nearFlowerPot) { + this.serverAirTicks = 0; + } + } + + private void cacheBlocksLegacy() { + this.blockX = NumberConversions.floor(this.x); + this.blockY = NumberConversions.floor(this.y); + this.blockZ = NumberConversions.floor(this.z); + this.nearbyBlocks = BlockUtil.getNearbyBlocksAsync(this.world, this.blockX, this.blockY, this.blockZ, 1); + this.blocksBelow = PlayerUtil.getBlocksBelow(this.data); + this.blocksAbove = PlayerUtil.getBlocksAbove(this.data); + this.blocksAround = PlayerUtil.getBlocksAround(this.data); + this.glitchedBlocksAbove = PlayerUtil.getBlocksAboveGlitchedLegacy(this.data); + this.blockBelow = BlockUtil.getBlockTypeASync(this.world, this.blockX, NumberConversions.floor(this.y - 1.0), this.blockZ); + this.blockBelow2 = BlockUtil.getBlockTypeASync(this.world, this.blockX, NumberConversions.floor(this.y - 2.0), this.blockZ); + this.blockBelow3 = BlockUtil.getBlockTypeASync(this.world, this.blockX, NumberConversions.floor(this.y - 3.0), this.blockZ); + this.onIce = PlayerUtil.isOnIce(this.data); + this.fullyStuck = PlayerUtil.isFullyStuck(this.data); + this.partiallyStuck = PlayerUtil.isPartiallyStuck(this.data); + this.collidingVertically = !StreamUtil.allMatch(this.blocksAbove, BlockUtil::isAir); + this.collidingHorizontally = !StreamUtil.allMatch(this.blocksAround, BlockUtil::isAir); + this.nearSolid = StreamUtil.anyMatch(this.nearbyBlocks, BlockUtil::isSolid); + this.touchingAir = (StreamUtil.allMatch(this.blocksAround, BlockUtil::isAir) && StreamUtil.allMatch(this.blocksBelow, BlockUtil::isAir)); + this.handleCollisionsLegacy(); + } + + private void handleCollisionsLegacy() { + final boolean nearSlime = false; + this.nearAmethyst = nearSlime; + this.nearEnchantmentTable = nearSlime; + this.nearPressurePlate = nearSlime; + this.nearBamboo = nearSlime; + this.nearSign = nearSlime; + this.nearCake = nearSlime; + this.nearChest = nearSlime; + this.nearLava = nearSlime; + this.nearFarmland = nearSlime; + this.nearBed = nearSlime; + this.nearSkull = nearSlime; + this.nearPane = nearSlime; + this.nearPiston = nearSlime; + this.nearLilyPad = nearSlime; + this.nearDoor = nearSlime; + this.nearHopper = nearSlime; + this.nearSlab = nearSlime; + this.nearRail = nearSlime; + this.nearBoat = nearSlime; + this.nearRepeater = nearSlime; + this.nearAnvil = nearSlime; + this.nearSnow = nearSlime; + this.nearFenceGate = nearSlime; + this.nearIce = nearSlime; + this.nearStair = nearSlime; + this.nearCauldron = nearSlime; + this.nearWall = nearSlime; + this.nearBrewingStand = nearSlime; + this.nearDaylightSensor = nearSlime; + this.nearLantern = nearSlime; + this.nearPath = nearSlime; + this.nearPortalFrame = nearSlime; + this.nearTrapdoor = nearSlime; + this.nearFlowerPot = nearSlime; + this.nearWeb = nearSlime; + this.nearClimbable = nearSlime; + this.nearSoulSand = nearSlime; + this.nearCarpet = nearSlime; + this.nearLiquid = nearSlime; + this.nearFence = nearSlime; + this.nearSlime = nearSlime; + if (this.nearbyBlocks != null && this.nearbyEntities != null) { + for (final Material material : this.nearbyBlocks) { + this.nearSlime |= BlockUtil.isSlime(material); + this.nearFence |= BlockUtil.isFence(material); + this.nearLiquid |= BlockUtil.isLiquid(material); + this.nearCarpet |= BlockUtil.isCarpet(material); + this.nearSoulSand |= BlockUtil.isSoulSand(material); + this.nearClimbable |= BlockUtil.isClimbable(material); + this.nearWeb |= BlockUtil.isWeb(material); + this.nearFlowerPot |= BlockUtil.isFlowerPot(material); + this.nearTrapdoor |= BlockUtil.isTrapdoor(material); + this.nearPortalFrame |= BlockUtil.isPortalFrame(material); + this.nearDaylightSensor |= BlockUtil.isDaylightSensor(material); + this.nearBrewingStand |= BlockUtil.isBrewingStand(material); + this.nearWall |= BlockUtil.isWall(material); + this.nearCauldron |= BlockUtil.isCauldron(material); + this.nearStair |= BlockUtil.isStair(material); + this.nearIce |= BlockUtil.isIce(material); + this.nearFenceGate |= BlockUtil.isFenceGate(material); + this.nearSnow |= BlockUtil.isSnow(material); + this.nearAnvil |= BlockUtil.isAnvil(material); + this.nearRepeater |= BlockUtil.isRepeater(material); + this.nearSlab |= BlockUtil.isSlab(material); + this.nearHopper |= BlockUtil.isHopper(material); + this.nearDoor |= BlockUtil.isDoor(material); + this.nearLilyPad |= BlockUtil.isLilyPad(material); + this.nearPiston |= BlockUtil.isPiston(material); + this.nearPane |= BlockUtil.isPane(material); + this.nearSkull |= BlockUtil.isSkull(material); + this.nearBed |= BlockUtil.isBed(material); + this.nearFarmland |= BlockUtil.isFarmland(material); + this.nearChest |= BlockUtil.isChest(material); + this.nearCake |= BlockUtil.isCake(material); + this.nearPath |= BlockUtil.isPath(material); + this.nearLantern |= BlockUtil.isLantern(material); + this.nearRail |= BlockUtil.isRail(material); + this.nearSign |= BlockUtil.isSign(material); + this.nearBamboo |= BlockUtil.isBamboo(material); + this.nearPressurePlate |= BlockUtil.isPressurePlate(material); + this.nearEnchantmentTable |= BlockUtil.isEnchantmentTable(material); + this.nearAmethyst |= BlockUtil.isAmethyst(material); + } + for (final Entity entity : this.nearbyEntities) { + this.nearBoat |= EntityUtil.isBoat(entity); + if (entity instanceof EnderDragon || entity instanceof EnderDragonPart) { + this.data.getActionProcessor().setSinceDragonDamageTicks(0); + } + if (entity instanceof TNTPrimed) { + this.data.getActionProcessor().setSinceExplosionTicks(0); + } + } + this.onClimbable = PlayerUtil.isOnClimbable(this.data); + this.inWeb = PlayerUtil.isInWeb(this.data); + this.inLiquid = PlayerUtil.isInLiquid(this.data); + this.fullySubmerged = PlayerUtil.isFullySubmerged(this.data); + } + if (this.nearBoat || this.nearShulker || this.nearTrapdoor || this.nearCarpet || this.nearBrewingStand || this.nearRepeater || this.nearDaylightSensor || this.nearSkull || this.nearLilyPad || this.nearFlowerPot) { + this.serverAirTicks = 0; + } + } + + public void handleVehicleMove(final WrappedPacketInVehicleMove wrapper) { + ++this.vehicleTicks; + this.lastBukkitVehicle = this.bukkitVehicle; + this.bukkitVehicle = this.data.getPlayer().getVehicle(); + if (this.lastBukkitVehicle != this.bukkitVehicle) { + this.vehicleTicks = 0; + } + this.vehicleX = wrapper.getX(); + this.vehicleY = wrapper.getY(); + this.vehicleZ = wrapper.getZ(); + this.lastVehicleDeltaX = this.vehicleDeltaX; + this.lastVehicleDeltaY = this.vehicleDeltaY; + this.lastVehicleDeltaZ = this.vehicleDeltaZ; + this.vehicleDeltaX = this.vehicleX - this.lastVehicleX; + this.vehicleDeltaY = this.vehicleY - this.lastVehicleY; + this.vehicleDeltaZ = this.vehicleZ - this.lastVehicleZ; + this.vehicleDeltaXZ = MathUtil.hypot(this.vehicleDeltaX, this.vehicleDeltaZ); + if (ServerUtil.isLowerThan1_13() && ServerUtil.isHigherThan1_9()) { + this.vehicleBlocks = BlockUtil.getNearbyBlocksAsync(this.world, NumberConversions.floor(this.vehicleX), NumberConversions.floor(this.vehicleY), NumberConversions.floor(this.vehicleZ), 1); + } + if (this.vehicleBlocks != null) { + final boolean b = false; + this.vehicleNearBed = b; + this.vehicleNearBubbleColumn = b; + this.vehicleNearSlime = b; + this.vehicleNearPiston = b; + this.vehicleNearLiquid = b; + this.vehicleNearIce = b; + for (final Material material : this.vehicleBlocks) { + this.vehicleNearIce |= BlockUtil.isIce(material); + this.vehicleNearLiquid |= BlockUtil.isLiquid(material); + this.vehicleNearPiston |= BlockUtil.isPiston(material); + this.vehicleNearSlime |= BlockUtil.isSlime(material); + this.vehicleNearBubbleColumn |= BlockUtil.isBubbleColumn(material); + this.vehicleNearBed |= BlockUtil.isBed(material); + } + this.vehicleInAir = StreamUtil.allMatch(this.vehicleBlocks, BlockUtil::isAir); + } + this.boatsAround = 0; + this.vehicleNearEntity = false; + if (this.nearbyEntities != null) { + for (final Entity entity : this.nearbyEntities) { + if (entity instanceof Boat) { + ++this.boatsAround; + } + if (entity instanceof LivingEntity) { + this.vehicleNearEntity = true; + } + } + } + if (this.vehicleNearIce) { + this.sinceVehicleNearIceTicks = 0; + } + else { + ++this.sinceVehicleNearIceTicks; + } + if (this.vehicleNearPiston) { + this.sinceVehicleNearPistonTicks = 0; + } + else { + ++this.sinceVehicleNearPistonTicks; + } + if (this.vehicleNearBed) { + this.sinceVehicleNearBedTicks = 0; + } + else { + ++this.sinceVehicleNearBedTicks; + } + if (this.vehicleNearLiquid) { + this.sinceVehicleNearLiquidTicks = 0; + } + else { + ++this.sinceVehicleNearLiquidTicks; + } + if (this.vehicleNearSlime) { + this.sinceVehicleNearSlimeTicks = 0; + } + else { + ++this.sinceVehicleNearSlimeTicks; + } + if (this.vehicleNearBubbleColumn) { + this.sinceVehicleNearBubbleColumnTicks = 0; + } + else { + ++this.sinceVehicleNearBubbleColumnTicks; + } + if (this.vehicleInAir) { + ++this.vehicleAirTicks; + } + else { + this.vehicleAirTicks = 0; + } + this.lastVehicleX = this.vehicleX; + this.lastVehicleY = this.vehicleY; + this.lastVehicleZ = this.vehicleZ; + } + + public void handleFlyingTicks() { + ++this.sinceGroundSpeedFailTicks; + ++this.ticksSinceGhostBlockSetback; + ++this.sinceFishingRodTicks; + ++this.sinceAttributeModifierTicks; + ++this.sinceSetbackTicks; + if (this.clientOnGround) { + ++this.clientGroundTicks; + } + else { + this.clientGroundTicks = 0; + } + if (!this.clientOnGround) { + ++this.clientAirTicks; + } + else { + this.clientAirTicks = 0; + } + } + + public void handlePositionTicks() { + ++this.sinceFlagTicks; + ++this.sinceFuckingEntityTicks; + if (this.touchingAir) { + ++this.serverAirTicks; + } + else { + this.serverAirTicks = 0; + } + if (this.mathematicallyOnGround) { + ++this.serverGroundTicks; + } + else { + this.serverGroundTicks = 0; + } + if (this.flySpeed > 0.11f) { + this.sinceHighFlySpeedTicks = 0; + } + else { + ++this.sinceHighFlySpeedTicks; + } + if (this.nearSlime || (this.blockBelow != null && BlockUtil.isSlime(this.blockBelow)) || (this.blockBelow2 != null && BlockUtil.isSlime(this.blockBelow2)) || (this.blockBelow3 != null && BlockUtil.isSlime(this.blockBelow3)) || (this.blockBelowModern != null && BlockUtil.isSlime(this.blockBelowModern)) || (this.blockBelow2Modern != null && BlockUtil.isSlime(this.blockBelow2Modern)) || (this.blockBelow3Modern != null && BlockUtil.isSlime(this.blockBelow3Modern))) { + this.sinceNearSlimeTicks = 0; + } + else { + ++this.sinceNearSlimeTicks; + } + ++this.sinceWaterLogTicks; + if (this.nearIce) { + this.sinceNearIceTicks = 0; + } + else { + ++this.sinceNearIceTicks; + } + if (this.data.getActionProcessor().isHasSpeed()) { + this.sinceSpeedTicks = 0; + } + else { + ++this.sinceSpeedTicks; + } + if (ServerUtil.isHigherThan1_8() && this.data.getPlayer().getGameMode() == GameMode.SPECTATOR) { + this.sinceSpectatorTicks = 0; + } + else { + ++this.sinceSpectatorTicks; + } + if (this.nearBed) { + this.sinceNearBedTicks = 0; + } + else { + ++this.sinceNearBedTicks; + } + if (this.nearFarmland) { + this.sinceNearFarmlandTicks = 0; + } + else { + ++this.sinceNearFarmlandTicks; + } + if (this.nearSlab) { + this.sinceNearSlabTicks = 0; + } + else { + ++this.sinceNearSlabTicks; + } + if (this.nearPiston) { + this.sinceNearPistonTicks = 0; + } + else { + ++this.sinceNearPistonTicks; + } + if (this.collidingEntity) { + this.sinceEntityCollisionTicks = 0; + } + else { + ++this.sinceEntityCollisionTicks; + } + if (this.data.getActionProcessor().isHasJumpBoost()) { + this.sinceJumpBoostTicks = 0; + } + else { + ++this.sinceJumpBoostTicks; + } + if (this.collidingVertically) { + this.sinceCollidingVerticallyTicks = 0; + } + else { + ++this.sinceCollidingVerticallyTicks; + } + if (this.collidingHorizontally) { + this.sinceCollidingHorizontallyTicks = 0; + } + else { + ++this.sinceCollidingHorizontallyTicks; + } + if (this.nearFrostedIce) { + this.sinceNearFrostedIceTicks = 0; + } + else { + ++this.sinceNearFrostedIceTicks; + } + if (this.nearFence) { + this.sinceNearFenceTicks = 0; + } + else { + ++this.sinceNearFenceTicks; + } + if (this.onIce) { + this.sinceIceTicks = 0; + } + else { + ++this.sinceIceTicks; + } + if (this.nearTrapdoor) { + this.sinceTrapdoorTicks = 0; + } + else { + ++this.sinceTrapdoorTicks; + } + if (this.nearWeb) { + this.sinceWebTicks = 0; + } + else { + ++this.sinceWebTicks; + } + if (this.nearClimbable) { + this.sinceNearClimbableTicks = 0; + } + else { + ++this.sinceNearClimbableTicks; + } + if (this.nearShulker || this.nearShulkerBox) { + this.sinceNearShulkerBoxTicks = 0; + } + else { + ++this.sinceNearShulkerBoxTicks; + } + if (this.nearScaffolding) { + this.sinceNearScaffoldingTicks = 0; + } + else { + ++this.sinceNearScaffoldingTicks; + } + if (this.inLiquid || this.nearLiquid) { + this.sinceLiquidTicks = 0; + } + else { + ++this.sinceLiquidTicks; + } + if (this.onClimbable) { + ++this.climbableTicks; + } + else { + this.climbableTicks = 0; + } + if (this.nearStair) { + this.sinceNearStairTicks = 0; + } + else { + ++this.sinceNearStairTicks; + } + if (this.blocksAround != null && StreamUtil.anyMatch(this.blocksAround, BlockUtil::isSlime)) { + this.sinceAroundSlimeTicks = 0; + } + else { + ++this.sinceAroundSlimeTicks; + } + if (this.blocksAround != null && StreamUtil.anyMatch(this.blocksAround, BlockUtil::isPiston)) { + this.sinceAroundPistonTicks = 0; + } + else { + ++this.sinceAroundPistonTicks; + } + if (this.blocksAround != null && StreamUtil.anyMatch(this.blocksAround, BlockUtil::isSlab)) { + this.sinceAroundSlabTicks = 0; + } + else { + ++this.sinceAroundSlabTicks; + } + if (this.data.getPlayer().isInsideVehicle() || this.data.getPlayer().getVehicle() != null) { + this.sinceVehicleTicks = 0; + } + else { + ++this.sinceVehicleTicks; + } + ++this.sinceFireworkTicks; + if (this.data.getPlayer().getAllowFlight() || this.allowFlight) { + this.sinceFlyingTicks = 0; + } + else { + ++this.sinceFlyingTicks; + } + if (ServerUtil.isHigherThan1_9()) { + if (this.data.getActionProcessor().isHasSlowFalling()) { + this.sinceSlowFallingTicks = 0; + } + else { + ++this.sinceSlowFallingTicks; + } + if (PlayerUtil.isSwimming(this.data.getPlayer()) || this.data.getActionProcessor().isPacketSwimming()) { + this.sinceSwimmingTicks = 0; + } + else { + ++this.sinceSwimmingTicks; + } + if (this.data.getActionProcessor().isBukkitGliding() || this.data.getActionProcessor().isPacketGliding()) { + this.sinceGlidingTicks = 0; + } + else { + ++this.sinceGlidingTicks; + } + if (PlayerUtil.isGliding(this.data.getPlayer())) { + ++this.glidingTicks; + } + else { + this.glidingTicks = 0; + } + if (ServerUtil.isHigherThan1_16() && this.nearSoulSand && this.data.getActionProcessor().getBoots() != null && this.data.getActionProcessor().getBoots().getEnchantmentLevel(Enchantment.SOUL_SPEED) > 0) { + this.sinceSoulSpeedTicks = 0; + } + else { + ++this.sinceSoulSpeedTicks; + } + if (this.data.getActionProcessor().isWearingElytra()) { + this.sinceElytraTicks = 0; + } + else { + ++this.sinceElytraTicks; + } + if (PlayerUtil.isRiptiding(this.data.getPlayer())) { + this.sinceRiptideTicks = 0; + } + else { + ++this.sinceRiptideTicks; + } + if (this.nearHoney) { + this.sinceHoneyTicks = 0; + } + else { + ++this.sinceHoneyTicks; + } + if (this.data.getActionProcessor().isHasLevitation()) { + this.sinceLevitationTicks = 0; + } + else { + ++this.sinceLevitationTicks; + } + if (PlayerUtil.hasDolphinsGrace(this.data.getPlayer())) { + this.sinceDolphinsGraceTicks = 0; + } + else { + ++this.sinceDolphinsGraceTicks; + } + if (this.inBubbleColumn || this.nearBubbleColumn) { + this.sinceBubbleColumnTicks = 0; + } + else { + ++this.sinceBubbleColumnTicks; + } + } + } + + public void handleBlockDig(final WrappedPacketInBlockDig wrapper) { + if (ServerUtil.isHigherThan1_9() && wrapper.getDigType() == WrappedPacketInBlockDig.PlayerDigType.RELEASE_USE_ITEM) { + final boolean liquid = this.sinceLiquidTicks < 30 || this.sinceWaterLogTicks < 30; + final boolean playerWeather = this.data.getPlayer().getPlayerWeather() == WeatherType.DOWNFALL; + final boolean rain = this.data.getPlayer().getWorld().hasStorm(); + if ((liquid || rain || playerWeather) && PlayerUtil.isHoldingTridentWithRiptide(this.data.getPlayer())) { + this.sinceRiptideTicks = 0; + } + } + } + + public boolean isNearGround() { + if (ServerUtil.isHigherThan1_13()) { + if (this.blockBelowModern != null && this.blockBelow2Modern != null) { + return !BlockUtil.isAir(this.blockBelowModern) || !BlockUtil.isAir(this.blockBelow2Modern); + } + } + else if (this.blockBelow != null && this.blockBelow2 != null) { + return !BlockUtil.isAir(this.blockBelow) || !BlockUtil.isAir(this.blockBelow2); + } + return false; + } + + public void handleArmAnimation() { + if (ServerUtil.isHigherThan1_9()) { + if (this.data.getPlayer().getInventory().getItemInMainHand().getType().toString().contains("FIREWORK")) { + this.sinceFireworkTicks = 0; + } + if (this.data.getPlayer().getInventory().getItemInOffHand().getType().toString().contains("FIREWORK")) { + this.sinceFireworkTicks = 0; + } + } + } + + public boolean isNearGroundModern() { + return this.blockBelowModern != null && this.blockBelow2Modern != null && this.blockBelow3Modern != null && (!BlockUtil.isAir(this.blockBelowModern) || !BlockUtil.isAir(this.blockBelow2Modern) || !BlockUtil.isAir(this.blockBelow3Modern)); + } + + public boolean isOnLiquid() { + return this.blocksBelow != null && StreamUtil.allMatch(this.blocksBelow, BlockUtil::isLiquid); + } + + public boolean isAirBelow() { + if (ServerUtil.isHigherThan1_13()) { + return this.blocksBelow != null && this.blocksUnderModern != null && StreamUtil.allMatch(this.blocksBelow, BlockUtil::isAir) && StreamUtil.allMatch(this.blocksUnderModern, BlockUtil::isAir); + } + return this.blocksBelow != null && StreamUtil.allMatch(this.blocksBelow, BlockUtil::isAir); + } + + public double getAcceleration() { + return Math.abs(this.deltaXZ - this.lastDeltaXZ); + } + + public void handleFishingRod() { + this.lastPulledByFishingRod = Vulcan.INSTANCE.getTickManager().getTicks(); + this.sinceFishingRodTicks = 0; + } + + public void parseForwardAndStrafe() { + final double angle = MathUtil.angleOf(this.lastZ, this.lastX, this.z, this.x); + final float rawYaw = this.data.getRotationProcessor().getYaw() % 360.0f; + final double yaw = (rawYaw >= 0.0f) ? rawYaw : ((double)(rawYaw + 360.0f)); + final double angleDeltaRaw = (double)(Math.round(MathUtil.getDistanceBetweenAngles360Raw(yaw, angle) / 5.0) * 5L); + final double angleDelta = (double)(Math.round(MathUtil.getDistanceBetweenAngles360(yaw, angle) / 5.0) * 5L); + float moveStrafing = 0.0f; + float moveForward = 0.0f; + if (angleDelta >= 0.0 && angleDelta < 90.0) { + ++moveForward; + } + else if (angleDelta > 90.0 && angleDelta <= 180.0) { + --moveForward; + } + if (angleDeltaRaw > 0.0 && angleDeltaRaw < 180.0) { + --moveStrafing; + } + else if (angleDeltaRaw > 180.0 && angleDeltaRaw < 360.0) { + ++moveStrafing; + } + this.moveForward = moveForward; + this.moveStrafing = moveStrafing; + } + + public void handleWaterlogged() { + this.sinceWaterLogTicks = 0; + this.lastWaterLogged = Vulcan.INSTANCE.getTickManager().getTicks(); + } + + private void handleGhostBlock() { + if (!Config.GHOST_BLOCK_FIX || ServerUtil.getTPS() < Config.GHOST_BLOCK_MIN_TPS) { + return; + } + final boolean exempt = this.data.getExemptProcessor().isExempt(ExemptType.LAGGED_NEAR_GROUND, ExemptType.BLOCK_PLACE_FAST, ExemptType.LAGGED_NEAR_GROUND_MODERN, ExemptType.FLIGHT, ExemptType.TELEPORT, ExemptType.SWIMMING, ExemptType.DEATH); + final boolean geyser = (Config.IGNORE_GEYSER_CLIENT_BRAND && this.data.getClientBrand().toLowerCase().contains("geyser")) || (Config.IGNORE_GEYSER_PREFIXES && this.data.getPlayer().getName().startsWith(Config.IGNORE_GEYSER_PREFIX)) || this.data.getPlayer().getUniqueId().toString().startsWith("00000"); + final boolean ghostBlock = this.serverAirTicks > Config.GHOST_BLOCK_MIN_TICKS && this.clientGroundTicks >= 1 && this.serverGroundTicks >= 1; + if (ghostBlock && !exempt && !geyser) { + final double ghostBlockBuffer = this.ghostBlockBuffer + 1.0; + this.ghostBlockBuffer = ghostBlockBuffer; + if (ghostBlockBuffer > Config.GHOST_BLOCK_MAX_BUFFER) { + if (Config.ENABLE_API) { + final VulcanGhostBlockEvent event = new VulcanGhostBlockEvent(this.data.getPlayer()); + Bukkit.getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + } + if (Config.GHOST_BLOCK_FIX_UPDATE_BLOCKS) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> { + final WrappedPacketOutBlockChange wrapper = new WrappedPacketOutBlockChange(new Location(this.world, this.blockX, this.blockY - 1, this.blockZ), this.world.getBlockAt(this.blockX, this.blockY - 1, this.blockZ).getType()); + final WrappedPacketOutBlockChange wrapper2 = new WrappedPacketOutBlockChange(new Location(this.world, this.blockX + 1, this.blockY - 1, this.blockZ), this.world.getBlockAt(this.blockX + 1, this.blockY - 1, this.blockZ).getType()); + final WrappedPacketOutBlockChange wrapper3 = new WrappedPacketOutBlockChange(new Location(this.world, this.blockX - 1, this.blockY - 1, this.blockZ), this.world.getBlockAt(this.blockX - 1, this.blockY - 1, this.blockZ).getType()); + final WrappedPacketOutBlockChange wrapper4 = new WrappedPacketOutBlockChange(new Location(this.world, this.blockX, this.blockY - 1, this.blockZ + 1), this.world.getBlockAt(this.blockX, this.blockY - 1, this.blockZ + 1).getType()); + final WrappedPacketOutBlockChange wrapper5 = new WrappedPacketOutBlockChange(new Location(this.world, this.blockX, this.blockY - 1, this.blockZ - 1), this.world.getBlockAt(this.blockX, this.blockY - 1, this.blockZ - 1).getType()); + final WrappedPacketOutBlockChange wrapper6 = new WrappedPacketOutBlockChange(new Location(this.world, this.blockX - 1, this.blockY - 1, this.blockZ - 1), this.world.getBlockAt(this.blockX - 1, this.blockY - 1, this.blockZ - 1).getType()); + final WrappedPacketOutBlockChange wrapper7 = new WrappedPacketOutBlockChange(new Location(this.world, this.blockX - 1, this.blockY - 1, this.blockZ + 1), this.world.getBlockAt(this.blockX - 1, this.blockY - 1, this.blockZ + 1).getType()); + final WrappedPacketOutBlockChange wrapper8 = new WrappedPacketOutBlockChange(new Location(this.world, this.blockX + 1, this.blockY - 1, this.blockZ + 1), this.world.getBlockAt(this.blockX - 1, this.blockY - 1, this.blockZ + 1).getType()); + final WrappedPacketOutBlockChange wrapper9 = new WrappedPacketOutBlockChange(new Location(this.world, this.blockX + 1, this.blockY - 1, this.blockZ - 1), this.world.getBlockAt(this.blockX + 1, this.blockY - 1, this.blockZ - 1).getType()); + PlayerUtil.sendPacket(this.data.getPlayer(), wrapper); + PlayerUtil.sendPacket(this.data.getPlayer(), wrapper2); + PlayerUtil.sendPacket(this.data.getPlayer(), wrapper3); + PlayerUtil.sendPacket(this.data.getPlayer(), wrapper4); + PlayerUtil.sendPacket(this.data.getPlayer(), wrapper5); + PlayerUtil.sendPacket(this.data.getPlayer(), wrapper6); + PlayerUtil.sendPacket(this.data.getPlayer(), wrapper7); + PlayerUtil.sendPacket(this.data.getPlayer(), wrapper8); + PlayerUtil.sendPacket(this.data.getPlayer(), wrapper9); + return; + }); + } + if (Config.GHOST_BLOCK_SETBACK) { + final float yaw = this.data.getRotationProcessor().getYaw(); + final float pitch = this.data.getRotationProcessor().getPitch(); + final Location setbackLocation = new Location(this.world, this.setbackX, this.setbackY, this.setbackZ, yaw, pitch); + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().teleport(setbackLocation, PlayerTeleportEvent.TeleportCause.UNKNOWN)); + this.ticksSinceGhostBlockSetback = 0; + this.lastGhostBlockSetback = Vulcan.INSTANCE.getTickManager().getTicks(); + } + if (Config.GHOST_BLOCK_MESSAGE_ENABLED) { + this.data.getPlayer().sendMessage(ColorUtil.translate(Config.GHOST_BLOCK_MESSAGE)); + } + if (Config.GHOST_BLOCK_STAFF_MESSAGE_ENABLED) { + Vulcan.INSTANCE.getAlertManager().sendMessage(Config.GHOST_BLOCK_STAFF_MESSAGE.replaceAll("%x%", Integer.toString(this.blockX)).replaceAll("%y%", Integer.toString(this.blockY)).replaceAll("%z%", Integer.toString(this.blockZ)).replaceAll("%ticks%", Integer.toString(this.serverAirTicks)).replaceAll("%world%", this.data.getPlayer().getWorld().getName()).replaceAll("%player%", this.data.getPlayer().getName())); + } + if (Config.GHOST_BLOCK_PRINT_TO_CONSOLE) { + Vulcan.INSTANCE.getPlugin().getLogger().log(Level.INFO, ColorUtil.translate(Config.GHOST_BLOCK_CONSOLE_MESSAGE.replaceAll("%ticks%", Integer.toString(this.serverAirTicks)).replaceAll("%player%", this.data.getPlayer().getName()).replaceAll("%world%", this.data.getPlayer().getWorld().getName()).replaceAll("%z%", Integer.toString(this.blockZ)).replaceAll("%y%", Integer.toString(this.blockY)).replaceAll("%x%", Integer.toString(this.blockX)))); + } + this.serverAirTicks = 0; + this.ghostBlockBuffer = 0.0; + } + } + else if (this.ghostBlockBuffer > 0.0) { + this.ghostBlockBuffer -= Config.GHOST_BLOCK_BUFFER_DECAY; + } + } + + public void handleTransaction(final WrappedPacketInTransaction wrapper) { + if (this.queuedAbilities.containsKey(wrapper.getActionNumber())) { + this.sinceFlyingTicks = 0; + final WrappedPacketOutAbilities confirmation = this.queuedAbilities.get(wrapper.getActionNumber()); + if (confirmation == null) { + return; + } + this.lastServerAbilities = Vulcan.INSTANCE.getTickManager().getTicks(); + this.allowFlight = confirmation.isFlightAllowed(); + this.walkSpeed = confirmation.getWalkSpeed() * 2.0f; + this.flySpeed = confirmation.getFlySpeed() * 2.0f; + this.queuedAbilities.remove(wrapper.getActionNumber()); + } + } + + public void handlePong(final WrappedPacketInPong wrapper) { + final short id = (short)wrapper.getId(); + if (this.queuedAbilities.containsKey(id)) { + this.sinceFlyingTicks = 0; + final WrappedPacketOutAbilities confirmation = this.queuedAbilities.get(id); + if (confirmation == null) { + return; + } + this.lastServerAbilities = Vulcan.INSTANCE.getTickManager().getTicks(); + this.allowFlight = confirmation.isFlightAllowed(); + this.walkSpeed = confirmation.getWalkSpeed() * 2.0f; + this.flySpeed = confirmation.getFlySpeed() * 2.0f; + this.queuedAbilities.remove(id); + } + } + + public void handleAbilities(final WrappedPacketOutAbilities wrapper) { + ++this.abilitiesTransactionId; + ++this.abilitiesPingId; + if (this.abilitiesTransactionId > -29769) { + this.abilitiesTransactionId = -30768; + } + if (this.abilitiesPingId > -29769) { + this.abilitiesPingId = -30768; + } + if (ServerUtil.isHigherThan1_17()) { + this.data.sendPing(this.abilitiesPingId); + } + else { + this.data.sendTransaction(this.abilitiesTransactionId); + } + this.queuedAbilities.put(this.abilitiesTransactionId, wrapper); + } + + public boolean isOnSoulSand() { + if (ServerUtil.isHigherThan1_13()) { + return this.nearbyBlocksModern != null && !this.nearbyBlocksModern.isEmpty() && BlockUtil.isSoulSandOnly(this.nearbyBlocksModern.get(16)); + } + return this.nearbyBlocks != null && !this.nearbyBlocks.isEmpty() && BlockUtil.isSoulSandOnly(this.nearbyBlocks.get(16)); + } + + public boolean isOnHoney() { + if (ServerUtil.isHigherThan1_13()) { + return this.nearbyBlocksModern != null && !this.nearbyBlocksModern.isEmpty() && BlockUtil.isHoney(this.nearbyBlocksModern.get(16)); + } + return this.nearbyBlocks != null && !this.nearbyBlocks.isEmpty() && BlockUtil.isHoney(this.nearbyBlocks.get(16)); + } + + public void setback() { + if (this.y < this.setbackY && Config.SETBACK_LOWER_POSITION) { + return; + } + this.sinceSetbackTicks = 0; + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().teleport(new Location(this.world, this.setbackX, this.setbackY, this.setbackZ, this.data.getRotationProcessor().getYaw(), this.data.getRotationProcessor().getPitch()), PlayerTeleportEvent.TeleportCause.UNKNOWN)); + } + + public void handleUnloadedChunk() { + if (!Config.UNLOADED_CHUNK_SETBACK) { + return; + } + final boolean exempt = this.data.getExemptProcessor().isExempt(ExemptType.JOINED, ExemptType.TELEPORT, ExemptType.WORLD_CHANGE, ExemptType.CHUNK, ExemptType.WORLD_CHANGE, ExemptType.FLIGHT, ExemptType.ELYTRA, ExemptType.GLIDING, ExemptType.SLOW_FALLING) || this.data.getActionProcessor().getPositionTicksExisted() < 20 || this.data.getActionProcessor().isTeleporting(); + final double diff = Math.abs(Math.abs(this.deltaY) - 0.09800000190734881); + if (this.deltaY < -0.09000000357627869 && !this.clientOnGround && !exempt && diff < 0.001) { + final double unloadedChunkBuffer = this.unloadedChunkBuffer + 1.0; + this.unloadedChunkBuffer = unloadedChunkBuffer; + if (unloadedChunkBuffer > Config.MAX_UNLOADED_CHUNK_TICKS) { + final float yaw = this.data.getRotationProcessor().getYaw(); + final float pitch = this.data.getRotationProcessor().getPitch(); + final Location setbackLocation = new Location(this.world, this.setbackX, this.setbackY, this.setbackZ, yaw, pitch); + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> this.data.getPlayer().teleport(setbackLocation, PlayerTeleportEvent.TeleportCause.UNKNOWN)); + if (!Config.UNLOADED_CHUNK_SETBACK_MESSAGE.equals("")) { + Vulcan.INSTANCE.getAlertManager().sendMessage(Config.UNLOADED_CHUNK_SETBACK_MESSAGE.replaceAll("%x%", Integer.toString(this.blockX)).replaceAll("%y%", Integer.toString(this.blockY)).replaceAll("%z%", Integer.toString(this.blockZ)).replaceAll("%ticks%", Integer.toString(this.serverAirTicks)).replaceAll("%world%", this.data.getPlayer().getWorld().getName()).replaceAll("%player%", this.data.getPlayer().getName())); + } + this.unloadedChunkBuffer = 0.0; + } + else if (this.unloadedChunkBuffer > 0.0) { + this.unloadedChunkBuffer -= 0.025; + } + } + } + + public PlayerData getData() { + return this.data; + } + + public boolean isNearFence() { + return this.nearFence; + } + + public boolean isNearLiquid() { + return this.nearLiquid; + } + + public boolean isNearSlime() { + return this.nearSlime; + } + + public boolean isNearSoulSand() { + return this.nearSoulSand; + } + + public boolean isNearClimbable() { + return this.nearClimbable; + } + + public boolean isNearWeb() { + return this.nearWeb; + } + + public boolean isNearLilyPad() { + return this.nearLilyPad; + } + + public boolean isNearDaylightSensor() { + return this.nearDaylightSensor; + } + + public boolean isNearBrewingStand() { + return this.nearBrewingStand; + } + + public boolean isNearWall() { + return this.nearWall; + } + + public boolean isNearStair() { + return this.nearStair; + } + + public boolean isNearSlab() { + return this.nearSlab; + } + + public boolean isNearHoney() { + return this.nearHoney; + } + + public boolean isNearScaffolding() { + return this.nearScaffolding; + } + + public boolean isNearTrapdoor() { + return this.nearTrapdoor; + } + + public boolean isNearSkull() { + return this.nearSkull; + } + + public boolean isNearPortalFrame() { + return this.nearPortalFrame; + } + + public boolean isNearCampfire() { + return this.nearCampfire; + } + + public boolean isNearSweetBerries() { + return this.nearSweetBerries; + } + + public boolean isNearShulkerBox() { + return this.nearShulkerBox; + } + + public boolean isVehicleNearBubbleColumn() { + return this.vehicleNearBubbleColumn; + } + + public boolean isNearSnow() { + return this.nearSnow; + } + + public boolean isNearAnvil() { + return this.nearAnvil; + } + + public boolean isNearEndRod() { + return this.nearEndRod; + } + + public boolean isNearChain() { + return this.nearChain; + } + + public boolean isNearPiston() { + return this.nearPiston; + } + + public boolean isNearDoor() { + return this.nearDoor; + } + + public boolean isTouchingAir() { + return this.touchingAir; + } + + public boolean isNearCauldron() { + return this.nearCauldron; + } + + public boolean isNearLava() { + return this.nearLava; + } + + public boolean isNearHopper() { + return this.nearHopper; + } + + public boolean isNearFenceGate() { + return this.nearFenceGate; + } + + public boolean isNearFlowerPot() { + return this.nearFlowerPot; + } + + public boolean isOnClimbable() { + return this.onClimbable; + } + + public boolean isInWeb() { + return this.inWeb; + } + + public boolean isInBubbleColumn() { + return this.inBubbleColumn; + } + + public boolean isFullySubmerged() { + return this.fullySubmerged; + } + + public boolean isInLiquid() { + return this.inLiquid; + } + + public boolean isCollidingVertically() { + return this.collidingVertically; + } + + public boolean isNearKelp() { + return this.nearKelp; + } + + public boolean isFullyStuck() { + return this.fullyStuck; + } + + public boolean isPartiallyStuck() { + return this.partiallyStuck; + } + + public boolean isOnIce() { + return this.onIce; + } + + public boolean isClientOnGround() { + return this.clientOnGround; + } + + public boolean isMathematicallyOnGround() { + return this.mathematicallyOnGround; + } + + public boolean isNearShulker() { + return this.nearShulker; + } + + public boolean isNearBoat() { + return this.nearBoat; + } + + public boolean isNearBell() { + return this.nearBell; + } + + public boolean isNearBed() { + return this.nearBed; + } + + public boolean isNearCarpet() { + return this.nearCarpet; + } + + public boolean isNearLectern() { + return this.nearLectern; + } + + public boolean isNearTurtleEgg() { + return this.nearTurtleEgg; + } + + public boolean isNearSeaPickle() { + return this.nearSeaPickle; + } + + public boolean isNearIce() { + return this.nearIce; + } + + public boolean isNearConduit() { + return this.nearConduit; + } + + public boolean isCollidingHorizontally() { + return this.collidingHorizontally; + } + + public boolean isNearRepeater() { + return this.nearRepeater; + } + + public boolean isNearSolid() { + return this.nearSolid; + } + + public boolean isNearPane() { + return this.nearPane; + } + + public boolean isVehicleNearIce() { + return this.vehicleNearIce; + } + + public boolean isVehicleNearLiquid() { + return this.vehicleNearLiquid; + } + + public boolean isVehicleNearSlime() { + return this.vehicleNearSlime; + } + + public boolean isVehicleInAir() { + return this.vehicleInAir; + } + + public boolean isMoving() { + return this.moving; + } + + public boolean isNearFrostedIce() { + return this.nearFrostedIce; + } + + public boolean isNearBubbleColumn() { + return this.nearBubbleColumn; + } + + public boolean isNearFarmland() { + return this.nearFarmland; + } + + public boolean isLastClientOnGround() { + return this.lastClientOnGround; + } + + public boolean isAllowFlight() { + return this.allowFlight; + } + + public boolean isNearSeaGrass() { + return this.nearSeaGrass; + } + + public boolean isNearChest() { + return this.nearChest; + } + + public boolean isVehicleNearPiston() { + return this.vehicleNearPiston; + } + + public boolean isNearCake() { + return this.nearCake; + } + + public boolean isVehicleNearBed() { + return this.vehicleNearBed; + } + + public boolean isNearAmethyst() { + return this.nearAmethyst; + } + + public boolean isNearDripstone() { + return this.nearDripstone; + } + + public boolean isNearPowderSnow() { + return this.nearPowderSnow; + } + + public boolean isSetbackGround() { + return this.setbackGround; + } + + public boolean isCollidingEntity() { + return this.collidingEntity; + } + + public boolean isLastLastClientOnGround() { + return this.lastLastClientOnGround; + } + + public boolean isVehicleNearEntity() { + return this.vehicleNearEntity; + } + + public boolean isNearPath() { + return this.nearPath; + } + + public boolean isNearLantern() { + return this.nearLantern; + } + + public boolean isNearBorder() { + return this.nearBorder; + } + + public boolean isNearRail() { + return this.nearRail; + } + + public boolean isNearSign() { + return this.nearSign; + } + + public boolean isNearBamboo() { + return this.nearBamboo; + } + + public boolean isNearPressurePlate() { + return this.nearPressurePlate; + } + + public boolean isFuckedPosition() { + return this.fuckedPosition; + } + + public boolean isNearEnchantmentTable() { + return this.nearEnchantmentTable; + } + + public Location getFrom() { + return this.from; + } + + public Location getTo() { + return this.to; + } + + public short getAbilitiesTransactionId() { + return this.abilitiesTransactionId; + } + + public short getAbilitiesPingId() { + return this.abilitiesPingId; + } + + public Map getQueuedAbilities() { + return this.queuedAbilities; + } + + public boolean isFrozen() { + return this.frozen; + } + + public List getNearbyEntities() { + return this.nearbyEntities; + } + + public Material getBlockBelow() { + return this.blockBelow; + } + + public Material getBlockBelow2() { + return this.blockBelow2; + } + + public Material getBlockBelow3() { + return this.blockBelow3; + } + + public List getNearbyBlocks() { + return this.nearbyBlocks; + } + + public List getBlocksBelow() { + return this.blocksBelow; + } + + public List getBlocksAbove() { + return this.blocksAbove; + } + + public List getBlocksAround() { + return this.blocksAround; + } + + public List getGlitchedBlocksAbove() { + return this.glitchedBlocksAbove; + } + + public List getNearbyBlocksModern() { + return this.nearbyBlocksModern; + } + + public List getVehicleBlocks() { + return this.vehicleBlocks; + } + + public List getBlocksUnderModern() { + return this.blocksUnderModern; + } + + public Material getBlockBelowModern() { + return this.blockBelowModern; + } + + public Material getBlockBelow2Modern() { + return this.blockBelow2Modern; + } + + public Material getBlockBelow3Modern() { + return this.blockBelow3Modern; + } + + public double getX() { + return this.x; + } + + public double getY() { + return this.y; + } + + public double getZ() { + return this.z; + } + + public double getLastX() { + return this.lastX; + } + + public double getLastY() { + return this.lastY; + } + + public double getLastZ() { + return this.lastZ; + } + + public double getDeltaX() { + return this.deltaX; + } + + public double getDeltaY() { + return this.deltaY; + } + + public double getDeltaZ() { + return this.deltaZ; + } + + public double getDeltaXZ() { + return this.deltaXZ; + } + + public double getDeltaXYZ() { + return this.deltaXYZ; + } + + public double getLastDeltaX() { + return this.lastDeltaX; + } + + public double getLastDeltaZ() { + return this.lastDeltaZ; + } + + public double getLastDeltaY() { + return this.lastDeltaY; + } + + public double getLastDeltaXZ() { + return this.lastDeltaXZ; + } + + public double getVehicleX() { + return this.vehicleX; + } + + public double getVehicleY() { + return this.vehicleY; + } + + public double getVehicleZ() { + return this.vehicleZ; + } + + public double getLastVehicleX() { + return this.lastVehicleX; + } + + public double getLastVehicleY() { + return this.lastVehicleY; + } + + public double getLastVehicleZ() { + return this.lastVehicleZ; + } + + public double getLastVehicleDeltaX() { + return this.lastVehicleDeltaX; + } + + public double getLastVehicleDeltaY() { + return this.lastVehicleDeltaY; + } + + public double getLastVehicleDeltaZ() { + return this.lastVehicleDeltaZ; + } + + public double getVehicleDeltaX() { + return this.vehicleDeltaX; + } + + public double getVehicleDeltaY() { + return this.vehicleDeltaY; + } + + public double getVehicleDeltaZ() { + return this.vehicleDeltaZ; + } + + public double getVehicleDeltaXZ() { + return this.vehicleDeltaXZ; + } + + public double getLastOnGroundX() { + return this.lastOnGroundX; + } + + public double getLastOnGroundY() { + return this.lastOnGroundY; + } + + public double getLastOnGroundZ() { + return this.lastOnGroundZ; + } + + public double getSetbackX() { + return this.setbackX; + } + + public double getSetbackY() { + return this.setbackY; + } + + public double getSetbackZ() { + return this.setbackZ; + } + + public double getGhostBlockBuffer() { + return this.ghostBlockBuffer; + } + + public double getNewSetbackX() { + return this.newSetbackX; + } + + public double getNewSetbackY() { + return this.newSetbackY; + } + + public double getNewSetbackZ() { + return this.newSetbackZ; + } + + public double getGhostBlockSetbackX() { + return this.ghostBlockSetbackX; + } + + public double getGhostBlockSetbackY() { + return this.ghostBlockSetbackY; + } + + public double getGhostBlockSetbackZ() { + return this.ghostBlockSetbackZ; + } + + public double getLastLegitX() { + return this.lastLegitX; + } + + public double getLastLegitY() { + return this.lastLegitY; + } + + public double getLastLegitZ() { + return this.lastLegitZ; + } + + public double getLastLastX() { + return this.lastLastX; + } + + public double getLastLastY() { + return this.lastLastY; + } + + public double getLastLastZ() { + return this.lastLastZ; + } + + public double getFirstJoinX() { + return this.firstJoinX; + } + + public double getFirstJoinY() { + return this.firstJoinY; + } + + public double getFirstJoinZ() { + return this.firstJoinZ; + } + + public double getUnloadedChunkBuffer() { + return this.unloadedChunkBuffer; + } + + public int getSinceVehicleTicks() { + return this.sinceVehicleTicks; + } + + public int getSinceFlyingTicks() { + return this.sinceFlyingTicks; + } + + public int getSinceTrapdoorTicks() { + return this.sinceTrapdoorTicks; + } + + public int getClientAirTicks() { + return this.clientAirTicks; + } + + public int getClientGroundTicks() { + return this.clientGroundTicks; + } + + public int getSinceSwimmingTicks() { + return this.sinceSwimmingTicks; + } + + public int getSinceRiptideTicks() { + return this.sinceRiptideTicks; + } + + public int getSinceGlidingTicks() { + return this.sinceGlidingTicks; + } + + public int getSinceIceTicks() { + return this.sinceIceTicks; + } + + public int getSinceDolphinsGraceTicks() { + return this.sinceDolphinsGraceTicks; + } + + public int getSinceLevitationTicks() { + return this.sinceLevitationTicks; + } + + public int getSinceBubbleColumnTicks() { + return this.sinceBubbleColumnTicks; + } + + public int getGlidingTicks() { + return this.glidingTicks; + } + + public int getSinceSlowFallingTicks() { + return this.sinceSlowFallingTicks; + } + + public int getServerAirTicks() { + return this.serverAirTicks; + } + + public int getServerGroundTicks() { + return this.serverGroundTicks; + } + + public int getSinceWebTicks() { + return this.sinceWebTicks; + } + + public int getSinceLiquidTicks() { + return this.sinceLiquidTicks; + } + + public int getClimbableTicks() { + return this.climbableTicks; + } + + public int getSinceJumpBoostTicks() { + return this.sinceJumpBoostTicks; + } + + public int getSinceNearSlimeTicks() { + return this.sinceNearSlimeTicks; + } + + public int getSinceHoneyTicks() { + return this.sinceHoneyTicks; + } + + public int getSinceCollidingVerticallyTicks() { + return this.sinceCollidingVerticallyTicks; + } + + public int getSinceNearFenceTicks() { + return this.sinceNearFenceTicks; + } + + public int getSinceSoulSpeedTicks() { + return this.sinceSoulSpeedTicks; + } + + public int getSinceNearBedTicks() { + return this.sinceNearBedTicks; + } + + public int getLastPulledByFishingRod() { + return this.lastPulledByFishingRod; + } + + public int getVehicleTicks() { + return this.vehicleTicks; + } + + public int getSinceFireworkTicks() { + return this.sinceFireworkTicks; + } + + public int getSinceNearIceTicks() { + return this.sinceNearIceTicks; + } + + public int getSinceNearPistonTicks() { + return this.sinceNearPistonTicks; + } + + public int getLastWaterLogged() { + return this.lastWaterLogged; + } + + public int getSinceSpeedTicks() { + return this.sinceSpeedTicks; + } + + public int getLastAttributeModifier() { + return this.lastAttributeModifier; + } + + public int getSinceAroundSlimeTicks() { + return this.sinceAroundSlimeTicks; + } + + public int getSinceAroundPistonTicks() { + return this.sinceAroundPistonTicks; + } + + public int getSinceVehicleNearIceTicks() { + return this.sinceVehicleNearIceTicks; + } + + public int getSinceVehicleNearLiquidTicks() { + return this.sinceVehicleNearLiquidTicks; + } + + public int getSinceVehicleNearSlimeTicks() { + return this.sinceVehicleNearSlimeTicks; + } + + public int getSinceVehicleNearBubbleColumnTicks() { + return this.sinceVehicleNearBubbleColumnTicks; + } + + public int getBlockX() { + return this.blockX; + } + + public int getBlockY() { + return this.blockY; + } + + public int getBlockZ() { + return this.blockZ; + } + + public int getSinceNearFrostedIceTicks() { + return this.sinceNearFrostedIceTicks; + } + + public int getSinceNearScaffoldingTicks() { + return this.sinceNearScaffoldingTicks; + } + + public int getTicksSinceGhostBlockSetback() { + return this.ticksSinceGhostBlockSetback; + } + + public int getLastServerAbilities() { + return this.lastServerAbilities; + } + + public int getVehicleAirTicks() { + return this.vehicleAirTicks; + } + + public int getSinceNearShulkerBoxTicks() { + return this.sinceNearShulkerBoxTicks; + } + + public int getSinceElytraTicks() { + return this.sinceElytraTicks; + } + + public int getLastGhostBlockSetback() { + return this.lastGhostBlockSetback; + } + + public int getSinceNearFarmlandTicks() { + return this.sinceNearFarmlandTicks; + } + + public int getSinceNearStairTicks() { + return this.sinceNearStairTicks; + } + + public int getSinceNearSlabTicks() { + return this.sinceNearSlabTicks; + } + + public int getSinceEntityCollisionTicks() { + return this.sinceEntityCollisionTicks; + } + + public int getSinceVehicleNearPistonTicks() { + return this.sinceVehicleNearPistonTicks; + } + + public int getSinceFishingRodTicks() { + return this.sinceFishingRodTicks; + } + + public int getSinceAttributeModifierTicks() { + return this.sinceAttributeModifierTicks; + } + + public int getSinceHighFlySpeedTicks() { + return this.sinceHighFlySpeedTicks; + } + + public int getSinceAroundSlabTicks() { + return this.sinceAroundSlabTicks; + } + + public int getSinceVehicleNearBedTicks() { + return this.sinceVehicleNearBedTicks; + } + + public int getSinceWaterLogTicks() { + return this.sinceWaterLogTicks; + } + + public int getSinceGroundSpeedFailTicks() { + return this.sinceGroundSpeedFailTicks; + } + + public int getSinceNearClimbableTicks() { + return this.sinceNearClimbableTicks; + } + + public int getBoatsAround() { + return this.boatsAround; + } + + public int getSinceSetbackTicks() { + return this.sinceSetbackTicks; + } + + public int getSinceCollidingHorizontallyTicks() { + return this.sinceCollidingHorizontallyTicks; + } + + public int getSinceFlagTicks() { + return this.sinceFlagTicks; + } + + public int getSinceFuckingEntityTicks() { + return this.sinceFuckingEntityTicks; + } + + public int getSinceSpectatorTicks() { + return this.sinceSpectatorTicks; + } + + public World getWorld() { + return this.world; + } + + public Entity getBukkitVehicle() { + return this.bukkitVehicle; + } + + public Entity getLastBukkitVehicle() { + return this.lastBukkitVehicle; + } + + public float getMoveForward() { + return this.moveForward; + } + + public float getMoveStrafing() { + return this.moveStrafing; + } + + public float getWalkSpeed() { + return this.walkSpeed; + } + + public float getFlySpeed() { + return this.flySpeed; + } + + public boolean isExemptFlight() { + return this.exemptFlight; + } + + public boolean isExemptCreative() { + return this.exemptCreative; + } + + public boolean isExemptJoined() { + return this.exemptJoined; + } + + public boolean isExemptLiquid() { + return this.exemptLiquid; + } + + public boolean isExemptLevitation() { + return this.exemptLevitation; + } + + public boolean isExemptSlowFalling() { + return this.exemptSlowFalling; + } + + public boolean isExemptRiptide() { + return this.exemptRiptide; + } + + public boolean isExemptVehicle() { + return this.exemptVehicle; + } + + public boolean isExemptLenientScaffolding() { + return this.exemptLenientScaffolding; + } + + public boolean isExemptBukkitVelocity() { + return this.exemptBukkitVelocity; + } + + public boolean isExemptGliding() { + return this.exemptGliding; + } + + public boolean isExemptElytra() { + return this.exemptElytra; + } + + public boolean isExemptTeleport() { + return this.exemptTeleport; + } + + public boolean isExemptEnderPearl() { + return this.exemptEnderPearl; + } + + public boolean isExemptChunk() { + return this.exemptChunk; + } + + public boolean isExemptComboMode() { + return this.exemptComboMode; + } + + public boolean isExemptMythicMob() { + return this.exemptMythicMob; + } + + public boolean isExemptClimbable() { + return this.exemptClimbable; + } + + public void setNearFence(final boolean nearFence) { + this.nearFence = nearFence; + } + + public void setNearLiquid(final boolean nearLiquid) { + this.nearLiquid = nearLiquid; + } + + public void setNearSlime(final boolean nearSlime) { + this.nearSlime = nearSlime; + } + + public void setNearSoulSand(final boolean nearSoulSand) { + this.nearSoulSand = nearSoulSand; + } + + public void setNearClimbable(final boolean nearClimbable) { + this.nearClimbable = nearClimbable; + } + + public void setNearWeb(final boolean nearWeb) { + this.nearWeb = nearWeb; + } + + public void setNearLilyPad(final boolean nearLilyPad) { + this.nearLilyPad = nearLilyPad; + } + + public void setNearDaylightSensor(final boolean nearDaylightSensor) { + this.nearDaylightSensor = nearDaylightSensor; + } + + public void setNearBrewingStand(final boolean nearBrewingStand) { + this.nearBrewingStand = nearBrewingStand; + } + + public void setNearWall(final boolean nearWall) { + this.nearWall = nearWall; + } + + public void setNearStair(final boolean nearStair) { + this.nearStair = nearStair; + } + + public void setNearSlab(final boolean nearSlab) { + this.nearSlab = nearSlab; + } + + public void setNearHoney(final boolean nearHoney) { + this.nearHoney = nearHoney; + } + + public void setNearScaffolding(final boolean nearScaffolding) { + this.nearScaffolding = nearScaffolding; + } + + public void setNearTrapdoor(final boolean nearTrapdoor) { + this.nearTrapdoor = nearTrapdoor; + } + + public void setNearSkull(final boolean nearSkull) { + this.nearSkull = nearSkull; + } + + public void setNearPortalFrame(final boolean nearPortalFrame) { + this.nearPortalFrame = nearPortalFrame; + } + + public void setNearCampfire(final boolean nearCampfire) { + this.nearCampfire = nearCampfire; + } + + public void setNearSweetBerries(final boolean nearSweetBerries) { + this.nearSweetBerries = nearSweetBerries; + } + + public void setNearShulkerBox(final boolean nearShulkerBox) { + this.nearShulkerBox = nearShulkerBox; + } + + public void setVehicleNearBubbleColumn(final boolean vehicleNearBubbleColumn) { + this.vehicleNearBubbleColumn = vehicleNearBubbleColumn; + } + + public void setNearSnow(final boolean nearSnow) { + this.nearSnow = nearSnow; + } + + public void setNearAnvil(final boolean nearAnvil) { + this.nearAnvil = nearAnvil; + } + + public void setNearEndRod(final boolean nearEndRod) { + this.nearEndRod = nearEndRod; + } + + public void setNearChain(final boolean nearChain) { + this.nearChain = nearChain; + } + + public void setNearPiston(final boolean nearPiston) { + this.nearPiston = nearPiston; + } + + public void setNearDoor(final boolean nearDoor) { + this.nearDoor = nearDoor; + } + + public void setTouchingAir(final boolean touchingAir) { + this.touchingAir = touchingAir; + } + + public void setNearCauldron(final boolean nearCauldron) { + this.nearCauldron = nearCauldron; + } + + public void setNearLava(final boolean nearLava) { + this.nearLava = nearLava; + } + + public void setNearHopper(final boolean nearHopper) { + this.nearHopper = nearHopper; + } + + public void setNearFenceGate(final boolean nearFenceGate) { + this.nearFenceGate = nearFenceGate; + } + + public void setNearFlowerPot(final boolean nearFlowerPot) { + this.nearFlowerPot = nearFlowerPot; + } + + public void setOnClimbable(final boolean onClimbable) { + this.onClimbable = onClimbable; + } + + public void setInWeb(final boolean inWeb) { + this.inWeb = inWeb; + } + + public void setInBubbleColumn(final boolean inBubbleColumn) { + this.inBubbleColumn = inBubbleColumn; + } + + public void setFullySubmerged(final boolean fullySubmerged) { + this.fullySubmerged = fullySubmerged; + } + + public void setInLiquid(final boolean inLiquid) { + this.inLiquid = inLiquid; + } + + public void setCollidingVertically(final boolean collidingVertically) { + this.collidingVertically = collidingVertically; + } + + public void setNearKelp(final boolean nearKelp) { + this.nearKelp = nearKelp; + } + + public void setFullyStuck(final boolean fullyStuck) { + this.fullyStuck = fullyStuck; + } + + public void setPartiallyStuck(final boolean partiallyStuck) { + this.partiallyStuck = partiallyStuck; + } + + public void setOnIce(final boolean onIce) { + this.onIce = onIce; + } + + public void setClientOnGround(final boolean clientOnGround) { + this.clientOnGround = clientOnGround; + } + + public void setMathematicallyOnGround(final boolean mathematicallyOnGround) { + this.mathematicallyOnGround = mathematicallyOnGround; + } + + public void setNearShulker(final boolean nearShulker) { + this.nearShulker = nearShulker; + } + + public void setNearBoat(final boolean nearBoat) { + this.nearBoat = nearBoat; + } + + public void setNearBell(final boolean nearBell) { + this.nearBell = nearBell; + } + + public void setNearBed(final boolean nearBed) { + this.nearBed = nearBed; + } + + public void setNearCarpet(final boolean nearCarpet) { + this.nearCarpet = nearCarpet; + } + + public void setNearLectern(final boolean nearLectern) { + this.nearLectern = nearLectern; + } + + public void setNearTurtleEgg(final boolean nearTurtleEgg) { + this.nearTurtleEgg = nearTurtleEgg; + } + + public void setNearSeaPickle(final boolean nearSeaPickle) { + this.nearSeaPickle = nearSeaPickle; + } + + public void setNearIce(final boolean nearIce) { + this.nearIce = nearIce; + } + + public void setNearConduit(final boolean nearConduit) { + this.nearConduit = nearConduit; + } + + public void setCollidingHorizontally(final boolean collidingHorizontally) { + this.collidingHorizontally = collidingHorizontally; + } + + public void setNearRepeater(final boolean nearRepeater) { + this.nearRepeater = nearRepeater; + } + + public void setNearSolid(final boolean nearSolid) { + this.nearSolid = nearSolid; + } + + public void setNearPane(final boolean nearPane) { + this.nearPane = nearPane; + } + + public void setVehicleNearIce(final boolean vehicleNearIce) { + this.vehicleNearIce = vehicleNearIce; + } + + public void setVehicleNearLiquid(final boolean vehicleNearLiquid) { + this.vehicleNearLiquid = vehicleNearLiquid; + } + + public void setVehicleNearSlime(final boolean vehicleNearSlime) { + this.vehicleNearSlime = vehicleNearSlime; + } + + public void setVehicleInAir(final boolean vehicleInAir) { + this.vehicleInAir = vehicleInAir; + } + + public void setMoving(final boolean moving) { + this.moving = moving; + } + + public void setNearFrostedIce(final boolean nearFrostedIce) { + this.nearFrostedIce = nearFrostedIce; + } + + public void setNearBubbleColumn(final boolean nearBubbleColumn) { + this.nearBubbleColumn = nearBubbleColumn; + } + + public void setNearFarmland(final boolean nearFarmland) { + this.nearFarmland = nearFarmland; + } + + public void setLastClientOnGround(final boolean lastClientOnGround) { + this.lastClientOnGround = lastClientOnGround; + } + + public void setAllowFlight(final boolean allowFlight) { + this.allowFlight = allowFlight; + } + + public void setNearSeaGrass(final boolean nearSeaGrass) { + this.nearSeaGrass = nearSeaGrass; + } + + public void setNearChest(final boolean nearChest) { + this.nearChest = nearChest; + } + + public void setVehicleNearPiston(final boolean vehicleNearPiston) { + this.vehicleNearPiston = vehicleNearPiston; + } + + public void setNearCake(final boolean nearCake) { + this.nearCake = nearCake; + } + + public void setVehicleNearBed(final boolean vehicleNearBed) { + this.vehicleNearBed = vehicleNearBed; + } + + public void setNearAmethyst(final boolean nearAmethyst) { + this.nearAmethyst = nearAmethyst; + } + + public void setNearDripstone(final boolean nearDripstone) { + this.nearDripstone = nearDripstone; + } + + public void setNearPowderSnow(final boolean nearPowderSnow) { + this.nearPowderSnow = nearPowderSnow; + } + + public void setSetbackGround(final boolean setbackGround) { + this.setbackGround = setbackGround; + } + + public void setCollidingEntity(final boolean collidingEntity) { + this.collidingEntity = collidingEntity; + } + + public void setLastLastClientOnGround(final boolean lastLastClientOnGround) { + this.lastLastClientOnGround = lastLastClientOnGround; + } + + public void setVehicleNearEntity(final boolean vehicleNearEntity) { + this.vehicleNearEntity = vehicleNearEntity; + } + + public void setNearPath(final boolean nearPath) { + this.nearPath = nearPath; + } + + public void setNearLantern(final boolean nearLantern) { + this.nearLantern = nearLantern; + } + + public void setNearBorder(final boolean nearBorder) { + this.nearBorder = nearBorder; + } + + public void setNearRail(final boolean nearRail) { + this.nearRail = nearRail; + } + + public void setNearSign(final boolean nearSign) { + this.nearSign = nearSign; + } + + public void setNearBamboo(final boolean nearBamboo) { + this.nearBamboo = nearBamboo; + } + + public void setNearPressurePlate(final boolean nearPressurePlate) { + this.nearPressurePlate = nearPressurePlate; + } + + public void setFuckedPosition(final boolean fuckedPosition) { + this.fuckedPosition = fuckedPosition; + } + + public void setNearEnchantmentTable(final boolean nearEnchantmentTable) { + this.nearEnchantmentTable = nearEnchantmentTable; + } + + public void setFrom(final Location from) { + this.from = from; + } + + public void setTo(final Location to) { + this.to = to; + } + + public void setAbilitiesTransactionId(final short abilitiesTransactionId) { + this.abilitiesTransactionId = abilitiesTransactionId; + } + + public void setAbilitiesPingId(final short abilitiesPingId) { + this.abilitiesPingId = abilitiesPingId; + } + + public void setBlockBelow(final Material blockBelow) { + this.blockBelow = blockBelow; + } + + public void setBlockBelow2(final Material blockBelow2) { + this.blockBelow2 = blockBelow2; + } + + public void setBlockBelow3(final Material blockBelow3) { + this.blockBelow3 = blockBelow3; + } + + public void setNearbyBlocks(final List nearbyBlocks) { + this.nearbyBlocks = nearbyBlocks; + } + + public void setBlocksBelow(final List blocksBelow) { + this.blocksBelow = blocksBelow; + } + + public void setBlocksAbove(final List blocksAbove) { + this.blocksAbove = blocksAbove; + } + + public void setBlocksAround(final List blocksAround) { + this.blocksAround = blocksAround; + } + + public void setGlitchedBlocksAbove(final List glitchedBlocksAbove) { + this.glitchedBlocksAbove = glitchedBlocksAbove; + } + + public void setX(final double x) { + this.x = x; + } + + public void setY(final double y) { + this.y = y; + } + + public void setZ(final double z) { + this.z = z; + } + + public void setLastX(final double lastX) { + this.lastX = lastX; + } + + public void setLastY(final double lastY) { + this.lastY = lastY; + } + + public void setLastZ(final double lastZ) { + this.lastZ = lastZ; + } + + public void setDeltaX(final double deltaX) { + this.deltaX = deltaX; + } + + public void setDeltaY(final double deltaY) { + this.deltaY = deltaY; + } + + public void setDeltaZ(final double deltaZ) { + this.deltaZ = deltaZ; + } + + public void setDeltaXZ(final double deltaXZ) { + this.deltaXZ = deltaXZ; + } + + public void setDeltaXYZ(final double deltaXYZ) { + this.deltaXYZ = deltaXYZ; + } + + public void setLastDeltaX(final double lastDeltaX) { + this.lastDeltaX = lastDeltaX; + } + + public void setLastDeltaZ(final double lastDeltaZ) { + this.lastDeltaZ = lastDeltaZ; + } + + public void setLastDeltaY(final double lastDeltaY) { + this.lastDeltaY = lastDeltaY; + } + + public void setLastDeltaXZ(final double lastDeltaXZ) { + this.lastDeltaXZ = lastDeltaXZ; + } + + public void setVehicleX(final double vehicleX) { + this.vehicleX = vehicleX; + } + + public void setVehicleY(final double vehicleY) { + this.vehicleY = vehicleY; + } + + public void setVehicleZ(final double vehicleZ) { + this.vehicleZ = vehicleZ; + } + + public void setLastVehicleX(final double lastVehicleX) { + this.lastVehicleX = lastVehicleX; + } + + public void setLastVehicleY(final double lastVehicleY) { + this.lastVehicleY = lastVehicleY; + } + + public void setLastVehicleZ(final double lastVehicleZ) { + this.lastVehicleZ = lastVehicleZ; + } + + public void setLastVehicleDeltaX(final double lastVehicleDeltaX) { + this.lastVehicleDeltaX = lastVehicleDeltaX; + } + + public void setLastVehicleDeltaY(final double lastVehicleDeltaY) { + this.lastVehicleDeltaY = lastVehicleDeltaY; + } + + public void setLastVehicleDeltaZ(final double lastVehicleDeltaZ) { + this.lastVehicleDeltaZ = lastVehicleDeltaZ; + } + + public void setVehicleDeltaX(final double vehicleDeltaX) { + this.vehicleDeltaX = vehicleDeltaX; + } + + public void setVehicleDeltaY(final double vehicleDeltaY) { + this.vehicleDeltaY = vehicleDeltaY; + } + + public void setVehicleDeltaZ(final double vehicleDeltaZ) { + this.vehicleDeltaZ = vehicleDeltaZ; + } + + public void setVehicleDeltaXZ(final double vehicleDeltaXZ) { + this.vehicleDeltaXZ = vehicleDeltaXZ; + } + + public void setLastOnGroundX(final double lastOnGroundX) { + this.lastOnGroundX = lastOnGroundX; + } + + public void setLastOnGroundY(final double lastOnGroundY) { + this.lastOnGroundY = lastOnGroundY; + } + + public void setLastOnGroundZ(final double lastOnGroundZ) { + this.lastOnGroundZ = lastOnGroundZ; + } + + public void setSetbackX(final double setbackX) { + this.setbackX = setbackX; + } + + public void setSetbackY(final double setbackY) { + this.setbackY = setbackY; + } + + public void setSetbackZ(final double setbackZ) { + this.setbackZ = setbackZ; + } + + public void setGhostBlockBuffer(final double ghostBlockBuffer) { + this.ghostBlockBuffer = ghostBlockBuffer; + } + + public void setNewSetbackX(final double newSetbackX) { + this.newSetbackX = newSetbackX; + } + + public void setNewSetbackY(final double newSetbackY) { + this.newSetbackY = newSetbackY; + } + + public void setNewSetbackZ(final double newSetbackZ) { + this.newSetbackZ = newSetbackZ; + } + + public void setGhostBlockSetbackX(final double ghostBlockSetbackX) { + this.ghostBlockSetbackX = ghostBlockSetbackX; + } + + public void setGhostBlockSetbackY(final double ghostBlockSetbackY) { + this.ghostBlockSetbackY = ghostBlockSetbackY; + } + + public void setGhostBlockSetbackZ(final double ghostBlockSetbackZ) { + this.ghostBlockSetbackZ = ghostBlockSetbackZ; + } + + public void setLastLegitX(final double lastLegitX) { + this.lastLegitX = lastLegitX; + } + + public void setLastLegitY(final double lastLegitY) { + this.lastLegitY = lastLegitY; + } + + public void setLastLegitZ(final double lastLegitZ) { + this.lastLegitZ = lastLegitZ; + } + + public void setLastLastX(final double lastLastX) { + this.lastLastX = lastLastX; + } + + public void setLastLastY(final double lastLastY) { + this.lastLastY = lastLastY; + } + + public void setLastLastZ(final double lastLastZ) { + this.lastLastZ = lastLastZ; + } + + public void setFirstJoinX(final double firstJoinX) { + this.firstJoinX = firstJoinX; + } + + public void setFirstJoinY(final double firstJoinY) { + this.firstJoinY = firstJoinY; + } + + public void setFirstJoinZ(final double firstJoinZ) { + this.firstJoinZ = firstJoinZ; + } + + public void setUnloadedChunkBuffer(final double unloadedChunkBuffer) { + this.unloadedChunkBuffer = unloadedChunkBuffer; + } + + public void setSinceVehicleTicks(final int sinceVehicleTicks) { + this.sinceVehicleTicks = sinceVehicleTicks; + } + + public void setSinceFlyingTicks(final int sinceFlyingTicks) { + this.sinceFlyingTicks = sinceFlyingTicks; + } + + public void setSinceTrapdoorTicks(final int sinceTrapdoorTicks) { + this.sinceTrapdoorTicks = sinceTrapdoorTicks; + } + + public void setClientAirTicks(final int clientAirTicks) { + this.clientAirTicks = clientAirTicks; + } + + public void setClientGroundTicks(final int clientGroundTicks) { + this.clientGroundTicks = clientGroundTicks; + } + + public void setSinceSwimmingTicks(final int sinceSwimmingTicks) { + this.sinceSwimmingTicks = sinceSwimmingTicks; + } + + public void setSinceRiptideTicks(final int sinceRiptideTicks) { + this.sinceRiptideTicks = sinceRiptideTicks; + } + + public void setSinceGlidingTicks(final int sinceGlidingTicks) { + this.sinceGlidingTicks = sinceGlidingTicks; + } + + public void setSinceIceTicks(final int sinceIceTicks) { + this.sinceIceTicks = sinceIceTicks; + } + + public void setSinceDolphinsGraceTicks(final int sinceDolphinsGraceTicks) { + this.sinceDolphinsGraceTicks = sinceDolphinsGraceTicks; + } + + public void setSinceLevitationTicks(final int sinceLevitationTicks) { + this.sinceLevitationTicks = sinceLevitationTicks; + } + + public void setSinceBubbleColumnTicks(final int sinceBubbleColumnTicks) { + this.sinceBubbleColumnTicks = sinceBubbleColumnTicks; + } + + public void setGlidingTicks(final int glidingTicks) { + this.glidingTicks = glidingTicks; + } + + public void setSinceSlowFallingTicks(final int sinceSlowFallingTicks) { + this.sinceSlowFallingTicks = sinceSlowFallingTicks; + } + + public void setServerAirTicks(final int serverAirTicks) { + this.serverAirTicks = serverAirTicks; + } + + public void setServerGroundTicks(final int serverGroundTicks) { + this.serverGroundTicks = serverGroundTicks; + } + + public void setSinceWebTicks(final int sinceWebTicks) { + this.sinceWebTicks = sinceWebTicks; + } + + public void setSinceLiquidTicks(final int sinceLiquidTicks) { + this.sinceLiquidTicks = sinceLiquidTicks; + } + + public void setClimbableTicks(final int climbableTicks) { + this.climbableTicks = climbableTicks; + } + + public void setSinceJumpBoostTicks(final int sinceJumpBoostTicks) { + this.sinceJumpBoostTicks = sinceJumpBoostTicks; + } + + public void setSinceNearSlimeTicks(final int sinceNearSlimeTicks) { + this.sinceNearSlimeTicks = sinceNearSlimeTicks; + } + + public void setSinceHoneyTicks(final int sinceHoneyTicks) { + this.sinceHoneyTicks = sinceHoneyTicks; + } + + public void setSinceCollidingVerticallyTicks(final int sinceCollidingVerticallyTicks) { + this.sinceCollidingVerticallyTicks = sinceCollidingVerticallyTicks; + } + + public void setSinceNearFenceTicks(final int sinceNearFenceTicks) { + this.sinceNearFenceTicks = sinceNearFenceTicks; + } + + public void setSinceSoulSpeedTicks(final int sinceSoulSpeedTicks) { + this.sinceSoulSpeedTicks = sinceSoulSpeedTicks; + } + + public void setSinceNearBedTicks(final int sinceNearBedTicks) { + this.sinceNearBedTicks = sinceNearBedTicks; + } + + public void setLastPulledByFishingRod(final int lastPulledByFishingRod) { + this.lastPulledByFishingRod = lastPulledByFishingRod; + } + + public void setVehicleTicks(final int vehicleTicks) { + this.vehicleTicks = vehicleTicks; + } + + public void setSinceFireworkTicks(final int sinceFireworkTicks) { + this.sinceFireworkTicks = sinceFireworkTicks; + } + + public void setSinceNearIceTicks(final int sinceNearIceTicks) { + this.sinceNearIceTicks = sinceNearIceTicks; + } + + public void setSinceNearPistonTicks(final int sinceNearPistonTicks) { + this.sinceNearPistonTicks = sinceNearPistonTicks; + } + + public void setLastWaterLogged(final int lastWaterLogged) { + this.lastWaterLogged = lastWaterLogged; + } + + public void setSinceSpeedTicks(final int sinceSpeedTicks) { + this.sinceSpeedTicks = sinceSpeedTicks; + } + + public void setLastAttributeModifier(final int lastAttributeModifier) { + this.lastAttributeModifier = lastAttributeModifier; + } + + public void setSinceAroundSlimeTicks(final int sinceAroundSlimeTicks) { + this.sinceAroundSlimeTicks = sinceAroundSlimeTicks; + } + + public void setSinceAroundPistonTicks(final int sinceAroundPistonTicks) { + this.sinceAroundPistonTicks = sinceAroundPistonTicks; + } + + public void setSinceVehicleNearIceTicks(final int sinceVehicleNearIceTicks) { + this.sinceVehicleNearIceTicks = sinceVehicleNearIceTicks; + } + + public void setSinceVehicleNearLiquidTicks(final int sinceVehicleNearLiquidTicks) { + this.sinceVehicleNearLiquidTicks = sinceVehicleNearLiquidTicks; + } + + public void setSinceVehicleNearSlimeTicks(final int sinceVehicleNearSlimeTicks) { + this.sinceVehicleNearSlimeTicks = sinceVehicleNearSlimeTicks; + } + + public void setSinceVehicleNearBubbleColumnTicks(final int sinceVehicleNearBubbleColumnTicks) { + this.sinceVehicleNearBubbleColumnTicks = sinceVehicleNearBubbleColumnTicks; + } + + public void setBlockX(final int blockX) { + this.blockX = blockX; + } + + public void setBlockY(final int blockY) { + this.blockY = blockY; + } + + public void setBlockZ(final int blockZ) { + this.blockZ = blockZ; + } + + public void setSinceNearFrostedIceTicks(final int sinceNearFrostedIceTicks) { + this.sinceNearFrostedIceTicks = sinceNearFrostedIceTicks; + } + + public void setSinceNearScaffoldingTicks(final int sinceNearScaffoldingTicks) { + this.sinceNearScaffoldingTicks = sinceNearScaffoldingTicks; + } + + public void setTicksSinceGhostBlockSetback(final int ticksSinceGhostBlockSetback) { + this.ticksSinceGhostBlockSetback = ticksSinceGhostBlockSetback; + } + + public void setLastServerAbilities(final int lastServerAbilities) { + this.lastServerAbilities = lastServerAbilities; + } + + public void setVehicleAirTicks(final int vehicleAirTicks) { + this.vehicleAirTicks = vehicleAirTicks; + } + + public void setSinceNearShulkerBoxTicks(final int sinceNearShulkerBoxTicks) { + this.sinceNearShulkerBoxTicks = sinceNearShulkerBoxTicks; + } + + public void setSinceElytraTicks(final int sinceElytraTicks) { + this.sinceElytraTicks = sinceElytraTicks; + } + + public void setLastGhostBlockSetback(final int lastGhostBlockSetback) { + this.lastGhostBlockSetback = lastGhostBlockSetback; + } + + public void setSinceNearFarmlandTicks(final int sinceNearFarmlandTicks) { + this.sinceNearFarmlandTicks = sinceNearFarmlandTicks; + } + + public void setSinceNearStairTicks(final int sinceNearStairTicks) { + this.sinceNearStairTicks = sinceNearStairTicks; + } + + public void setSinceNearSlabTicks(final int sinceNearSlabTicks) { + this.sinceNearSlabTicks = sinceNearSlabTicks; + } + + public void setSinceEntityCollisionTicks(final int sinceEntityCollisionTicks) { + this.sinceEntityCollisionTicks = sinceEntityCollisionTicks; + } + + public void setSinceVehicleNearPistonTicks(final int sinceVehicleNearPistonTicks) { + this.sinceVehicleNearPistonTicks = sinceVehicleNearPistonTicks; + } + + public void setSinceFishingRodTicks(final int sinceFishingRodTicks) { + this.sinceFishingRodTicks = sinceFishingRodTicks; + } + + public void setSinceAttributeModifierTicks(final int sinceAttributeModifierTicks) { + this.sinceAttributeModifierTicks = sinceAttributeModifierTicks; + } + + public void setSinceHighFlySpeedTicks(final int sinceHighFlySpeedTicks) { + this.sinceHighFlySpeedTicks = sinceHighFlySpeedTicks; + } + + public void setSinceAroundSlabTicks(final int sinceAroundSlabTicks) { + this.sinceAroundSlabTicks = sinceAroundSlabTicks; + } + + public void setSinceVehicleNearBedTicks(final int sinceVehicleNearBedTicks) { + this.sinceVehicleNearBedTicks = sinceVehicleNearBedTicks; + } + + public void setSinceWaterLogTicks(final int sinceWaterLogTicks) { + this.sinceWaterLogTicks = sinceWaterLogTicks; + } + + public void setSinceGroundSpeedFailTicks(final int sinceGroundSpeedFailTicks) { + this.sinceGroundSpeedFailTicks = sinceGroundSpeedFailTicks; + } + + public void setSinceNearClimbableTicks(final int sinceNearClimbableTicks) { + this.sinceNearClimbableTicks = sinceNearClimbableTicks; + } + + public void setBoatsAround(final int boatsAround) { + this.boatsAround = boatsAround; + } + + public void setSinceSetbackTicks(final int sinceSetbackTicks) { + this.sinceSetbackTicks = sinceSetbackTicks; + } + + public void setSinceCollidingHorizontallyTicks(final int sinceCollidingHorizontallyTicks) { + this.sinceCollidingHorizontallyTicks = sinceCollidingHorizontallyTicks; + } + + public void setSinceFlagTicks(final int sinceFlagTicks) { + this.sinceFlagTicks = sinceFlagTicks; + } + + public void setSinceFuckingEntityTicks(final int sinceFuckingEntityTicks) { + this.sinceFuckingEntityTicks = sinceFuckingEntityTicks; + } + + public void setSinceSpectatorTicks(final int sinceSpectatorTicks) { + this.sinceSpectatorTicks = sinceSpectatorTicks; + } + + public void setWorld(final World world) { + this.world = world; + } + + public void setBukkitVehicle(final Entity bukkitVehicle) { + this.bukkitVehicle = bukkitVehicle; + } + + public void setLastBukkitVehicle(final Entity lastBukkitVehicle) { + this.lastBukkitVehicle = lastBukkitVehicle; + } + + public void setMoveForward(final float moveForward) { + this.moveForward = moveForward; + } + + public void setMoveStrafing(final float moveStrafing) { + this.moveStrafing = moveStrafing; + } + + public void setWalkSpeed(final float walkSpeed) { + this.walkSpeed = walkSpeed; + } + + public void setFlySpeed(final float flySpeed) { + this.flySpeed = flySpeed; + } + + public void setExemptFlight(final boolean exemptFlight) { + this.exemptFlight = exemptFlight; + } + + public void setExemptCreative(final boolean exemptCreative) { + this.exemptCreative = exemptCreative; + } + + public void setExemptJoined(final boolean exemptJoined) { + this.exemptJoined = exemptJoined; + } + + public void setExemptLiquid(final boolean exemptLiquid) { + this.exemptLiquid = exemptLiquid; + } + + public void setExemptLevitation(final boolean exemptLevitation) { + this.exemptLevitation = exemptLevitation; + } + + public void setExemptSlowFalling(final boolean exemptSlowFalling) { + this.exemptSlowFalling = exemptSlowFalling; + } + + public void setExemptRiptide(final boolean exemptRiptide) { + this.exemptRiptide = exemptRiptide; + } + + public void setExemptVehicle(final boolean exemptVehicle) { + this.exemptVehicle = exemptVehicle; + } + + public void setExemptLenientScaffolding(final boolean exemptLenientScaffolding) { + this.exemptLenientScaffolding = exemptLenientScaffolding; + } + + public void setExemptBukkitVelocity(final boolean exemptBukkitVelocity) { + this.exemptBukkitVelocity = exemptBukkitVelocity; + } + + public void setExemptGliding(final boolean exemptGliding) { + this.exemptGliding = exemptGliding; + } + + public void setExemptElytra(final boolean exemptElytra) { + this.exemptElytra = exemptElytra; + } + + public void setExemptTeleport(final boolean exemptTeleport) { + this.exemptTeleport = exemptTeleport; + } + + public void setExemptEnderPearl(final boolean exemptEnderPearl) { + this.exemptEnderPearl = exemptEnderPearl; + } + + public void setExemptChunk(final boolean exemptChunk) { + this.exemptChunk = exemptChunk; + } + + public void setExemptComboMode(final boolean exemptComboMode) { + this.exemptComboMode = exemptComboMode; + } + + public void setExemptMythicMob(final boolean exemptMythicMob) { + this.exemptMythicMob = exemptMythicMob; + } + + public void setExemptClimbable(final boolean exemptClimbable) { + this.exemptClimbable = exemptClimbable; + } + + public void setFrozen(final boolean frozen) { + this.frozen = frozen; + } + + public void setNearbyEntities(final List nearbyEntities) { + this.nearbyEntities = nearbyEntities; + } + + public void setNearbyBlocksModern(final List nearbyBlocksModern) { + this.nearbyBlocksModern = nearbyBlocksModern; + } + + public void setVehicleBlocks(final List vehicleBlocks) { + this.vehicleBlocks = vehicleBlocks; + } + + public void setBlocksUnderModern(final List blocksUnderModern) { + this.blocksUnderModern = blocksUnderModern; + } + + public void setBlockBelowModern(final Material blockBelowModern) { + this.blockBelowModern = blockBelowModern; + } + + public void setBlockBelow2Modern(final Material blockBelow2Modern) { + this.blockBelow2Modern = blockBelow2Modern; + } + + public void setBlockBelow3Modern(final Material blockBelow3Modern) { + this.blockBelow3Modern = blockBelow3Modern; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/data/processor/RotationProcessor.java b/src/main/java/me/frep/vulcan/spigot/data/processor/RotationProcessor.java new file mode 100644 index 0000000..e9c468f --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/data/processor/RotationProcessor.java @@ -0,0 +1,260 @@ +package me.frep.vulcan.spigot.data.processor; + +import org.bukkit.util.Vector; +import me.frep.vulcan.spigot.util.value.Values; +import java.util.Collection; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.Vulcan; +import java.util.ArrayDeque; +import me.frep.vulcan.spigot.data.PlayerData; + +public class RotationProcessor +{ + private final PlayerData data; + private float yaw; + private float pitch; + private float lastYaw; + private float lastPitch; + private float deltaYaw; + private float deltaPitch; + private float lastDeltaYaw; + private float lastDeltaPitch; + private float yawAccel; + private float pitchAccel; + private float lastYawAccel; + private float lastPitchAccel; + private float rawMouseDeltaX; + private float rawMouseDeltaY; + private float fuckedPredictedPitch; + private float fuckedPredictedYaw; + private float lastFuckedPredictedPitch; + private float lastFuckedPredictedYaw; + private boolean invalidRate; + private boolean invalidSensitivity; + private boolean cinematic; + private double finalSensitivity; + private double mcpSensitivity; + private final ArrayDeque sensitivitySamples; + private int sensitivity; + private int lastRate; + private int lastInvalidSensitivity; + private int lastCinematic; + private int mouseDeltaX; + private int mouseDeltaY; + + public RotationProcessor(final PlayerData data) { + this.sensitivitySamples = new ArrayDeque(); + this.data = data; + } + + public void handle(final float yaw, final float pitch) { + this.lastYaw = this.yaw; + this.lastPitch = this.pitch; + this.yaw = yaw; + this.pitch = pitch; + this.lastDeltaYaw = this.deltaYaw; + this.lastDeltaPitch = this.deltaPitch; + this.deltaYaw = Math.abs(yaw - this.lastYaw); + this.deltaPitch = Math.abs(pitch - this.lastPitch); + this.lastPitchAccel = this.pitchAccel; + this.lastYawAccel = this.yawAccel; + this.yawAccel = Math.abs(this.deltaYaw - this.lastDeltaYaw); + this.pitchAccel = Math.abs(this.deltaPitch - this.lastDeltaPitch); + final float f = (float)this.mcpSensitivity * 0.6f + 0.2f; + final float gcd = f * f * f * 1.2f; + this.rawMouseDeltaX = this.deltaYaw / gcd; + this.rawMouseDeltaY = this.deltaPitch / gcd; + this.mouseDeltaX = (int)(this.deltaYaw / gcd); + this.mouseDeltaY = (int)(this.deltaPitch / gcd); + this.processCinematic(); + final float var3 = 0.512f; + final float var4 = 1.073742f; + final float expectedYaw = this.deltaYaw * 1.073742f + (float)(this.deltaYaw + 0.15); + final float expectedPitch = this.deltaPitch * 1.073742f - (float)(this.deltaPitch - 0.15); + final float pitchDiff = Math.abs(this.deltaPitch - expectedPitch); + final float yawDiff = Math.abs(this.deltaYaw - expectedYaw); + this.lastFuckedPredictedPitch = this.fuckedPredictedPitch; + this.lastFuckedPredictedYaw = this.fuckedPredictedYaw; + this.fuckedPredictedPitch = Math.abs(this.deltaPitch - pitchDiff); + this.fuckedPredictedYaw = Math.abs(this.deltaYaw - yawDiff); + if (this.deltaPitch > 0.1 && this.deltaPitch < 25.0f) { + this.processSensitivity(); + } + } + + public boolean hasValidSensitivity() { + return this.sensitivity > 0 && this.sensitivity < 200; + } + + private void processCinematic() { + final int now = Vulcan.INSTANCE.getTickManager().getTicks(); + final float differenceYaw = Math.abs(this.deltaYaw - this.lastDeltaYaw); + final float differencePitch = Math.abs(this.deltaPitch - this.lastDeltaPitch); + final float joltYaw = Math.abs(differenceYaw - this.deltaYaw); + final float joltPitch = Math.abs(differencePitch - this.deltaPitch); + if (joltYaw > 1.0 && joltPitch > 1.0) { + this.lastRate = now; + } + if (this.deltaPitch < 20.0f && this.finalSensitivity < 0.0) { + this.lastInvalidSensitivity = now; + } + if (this.invalidRate && this.invalidSensitivity) { + this.lastCinematic = now; + } + this.invalidRate = (now - this.lastRate > 3); + this.invalidSensitivity = (now - this.lastInvalidSensitivity < 3); + this.cinematic = (now - this.lastCinematic < 8); + } + + private void processSensitivity() { + final float gcd = (float)MathUtil.getGcd(this.deltaPitch, this.lastDeltaPitch); + final double sensitivityModifier = Math.cbrt(0.8333 * gcd); + final double sensitivityStepTwo = 1.666 * sensitivityModifier - 0.3333; + final double finalSensitivity = sensitivityStepTwo * 200.0; + this.finalSensitivity = finalSensitivity; + this.sensitivitySamples.add((int)finalSensitivity); + if (this.sensitivitySamples.size() == 40) { + this.sensitivity = MathUtil.getMode(this.sensitivitySamples); + if (this.hasValidSensitivity()) { + this.mcpSensitivity = Values.SENSITIVITY_MCP_VALUES.get(this.sensitivity); + } + this.sensitivitySamples.clear(); + } + } + + public boolean hasTooLowSensitivity() { + return this.sensitivity >= 0 && this.sensitivity < 50; + } + + public float getMovementAngle() { + final double deltaX = this.data.getPositionProcessor().getDeltaX(); + final double deltaZ = this.data.getPositionProcessor().getDeltaZ(); + final Vector movement = new Vector(deltaX, 0.0, deltaZ); + final Vector direction = new Vector(-Math.sin(this.yaw * 3.1415927f / 180.0f) * 1.0 * 0.5, 0.0, Math.cos(this.yaw * 3.1415927f / 180.0f) * 1.0 * 0.5); + return movement.angle(direction); + } + + public PlayerData getData() { + return this.data; + } + + public float getYaw() { + return this.yaw; + } + + public float getPitch() { + return this.pitch; + } + + public float getLastYaw() { + return this.lastYaw; + } + + public float getLastPitch() { + return this.lastPitch; + } + + public float getDeltaYaw() { + return this.deltaYaw; + } + + public float getDeltaPitch() { + return this.deltaPitch; + } + + public float getLastDeltaYaw() { + return this.lastDeltaYaw; + } + + public float getLastDeltaPitch() { + return this.lastDeltaPitch; + } + + public float getYawAccel() { + return this.yawAccel; + } + + public float getPitchAccel() { + return this.pitchAccel; + } + + public float getLastYawAccel() { + return this.lastYawAccel; + } + + public float getLastPitchAccel() { + return this.lastPitchAccel; + } + + public float getRawMouseDeltaX() { + return this.rawMouseDeltaX; + } + + public float getRawMouseDeltaY() { + return this.rawMouseDeltaY; + } + + public float getFuckedPredictedPitch() { + return this.fuckedPredictedPitch; + } + + public float getFuckedPredictedYaw() { + return this.fuckedPredictedYaw; + } + + public float getLastFuckedPredictedPitch() { + return this.lastFuckedPredictedPitch; + } + + public float getLastFuckedPredictedYaw() { + return this.lastFuckedPredictedYaw; + } + + public boolean isInvalidRate() { + return this.invalidRate; + } + + public boolean isInvalidSensitivity() { + return this.invalidSensitivity; + } + + public boolean isCinematic() { + return this.cinematic; + } + + public double getFinalSensitivity() { + return this.finalSensitivity; + } + + public double getMcpSensitivity() { + return this.mcpSensitivity; + } + + public ArrayDeque getSensitivitySamples() { + return this.sensitivitySamples; + } + + public int getSensitivity() { + return this.sensitivity; + } + + public int getLastRate() { + return this.lastRate; + } + + public int getLastInvalidSensitivity() { + return this.lastInvalidSensitivity; + } + + public int getLastCinematic() { + return this.lastCinematic; + } + + public int getMouseDeltaX() { + return this.mouseDeltaX; + } + + public int getMouseDeltaY() { + return this.mouseDeltaY; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/data/processor/VelocityProcessor.java b/src/main/java/me/frep/vulcan/spigot/data/processor/VelocityProcessor.java new file mode 100644 index 0000000..28232f0 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/data/processor/VelocityProcessor.java @@ -0,0 +1,171 @@ +package me.frep.vulcan.spigot.data.processor; + +import io.github.retrooper.packetevents.packetwrappers.play.in.pong.WrappedPacketInPong; +import io.github.retrooper.packetevents.packetwrappers.play.in.transaction.WrappedPacketInTransaction; +import org.bukkit.util.Vector; +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.Vulcan; +import me.frep.vulcan.spigot.util.MathUtil; +import java.util.HashMap; +import java.util.Map; +import me.frep.vulcan.spigot.data.PlayerData; + +public class VelocityProcessor +{ + private final PlayerData data; + private double velocityX; + private double velocityY; + private double velocityZ; + private double velocityXZ; + private long lastRepliedVelocityConfirmation; + private long lastSentVelocityTransaction; + private short transactionId; + private short pingId; + private VelocitySnapshot snapshot; + private final Map velocities; + private int tick; + private int transactionFlyingTicks; + private int sinceHighVelocityTicks; + + public VelocityProcessor(final PlayerData data) { + this.lastRepliedVelocityConfirmation = System.currentTimeMillis(); + this.lastSentVelocityTransaction = System.currentTimeMillis(); + this.transactionId = -31768; + this.pingId = -31768; + this.velocities = new HashMap(); + this.transactionFlyingTicks = 100; + this.sinceHighVelocityTicks = 100; + this.data = data; + } + + public void handle(final double velocityX, final double velocityY, final double velocityZ) { + this.velocityX = velocityX; + this.velocityY = velocityY; + this.velocityZ = velocityZ; + this.velocityXZ = MathUtil.hypot(velocityX, velocityZ); + if (this.velocityXZ > 1.0) { + this.sinceHighVelocityTicks = 0; + } + this.tick = Vulcan.INSTANCE.getTickManager().getTicks(); + ++this.transactionId; + ++this.pingId; + if (this.transactionId > -30769) { + this.transactionId = -31768; + } + if (this.pingId > -30769) { + this.pingId = -31768; + } + if (ServerUtil.isHigherThan1_17()) { + this.data.sendPing(this.pingId); + } + else { + PlayerUtil.sendTransaction(this.data.getPlayer(), this.transactionId); + } + this.lastSentVelocityTransaction = System.currentTimeMillis(); + this.velocities.put(this.transactionId, new VelocitySnapshot(new Vector(velocityX, velocityY, velocityZ), this.transactionId)); + final int lastDamage = this.data.getActionProcessor().getLastDamage(); + if (this.tick - lastDamage >= 3) { + this.data.getActionProcessor().handleBukkitVelocity(); + } + } + + public void handleFlying() { + ++this.transactionFlyingTicks; + ++this.sinceHighVelocityTicks; + } + + public void handleTransaction(final WrappedPacketInTransaction wrapper) { + if (this.velocities.containsKey(wrapper.getActionNumber())) { + this.transactionFlyingTicks = 0; + this.snapshot = this.velocities.get(wrapper.getActionNumber()); + this.velocities.remove(wrapper.getActionNumber()); + this.lastRepliedVelocityConfirmation = System.currentTimeMillis(); + } + } + + public void handlePong(final WrappedPacketInPong wrapper) { + final short id = (short)wrapper.getId(); + if (this.velocities.containsKey(id)) { + this.transactionFlyingTicks = 0; + this.snapshot = this.velocities.get(id); + this.velocities.remove(id); + this.lastRepliedVelocityConfirmation = System.currentTimeMillis(); + } + } + + public PlayerData getData() { + return this.data; + } + + public double getVelocityX() { + return this.velocityX; + } + + public double getVelocityY() { + return this.velocityY; + } + + public double getVelocityZ() { + return this.velocityZ; + } + + public double getVelocityXZ() { + return this.velocityXZ; + } + + public long getLastRepliedVelocityConfirmation() { + return this.lastRepliedVelocityConfirmation; + } + + public long getLastSentVelocityTransaction() { + return this.lastSentVelocityTransaction; + } + + public short getTransactionId() { + return this.transactionId; + } + + public short getPingId() { + return this.pingId; + } + + public VelocitySnapshot getSnapshot() { + return this.snapshot; + } + + public Map getVelocities() { + return this.velocities; + } + + public int getTick() { + return this.tick; + } + + public int getTransactionFlyingTicks() { + return this.transactionFlyingTicks; + } + + public int getSinceHighVelocityTicks() { + return this.sinceHighVelocityTicks; + } + + public class VelocitySnapshot + { + private final Vector velocity; + private final short transactionId; + + public VelocitySnapshot(final Vector velocity, final short transactionId) { + this.velocity = velocity; + this.transactionId = transactionId; + } + + public Vector getVelocity() { + return this.velocity; + } + + public short getTransactionId() { + return this.transactionId; + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/event/EventProcessor.java b/src/main/java/me/frep/vulcan/spigot/event/EventProcessor.java new file mode 100644 index 0000000..0144574 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/event/EventProcessor.java @@ -0,0 +1,519 @@ +package me.frep.vulcan.spigot.event; + +import org.bukkit.plugin.Plugin; +import java.util.Iterator; +import org.bukkit.OfflinePlayer; +import org.bukkit.Bukkit; +import java.util.ArrayList; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerKickEvent; +import org.bukkit.entity.Entity; +import org.bukkit.block.Block; +import me.frep.vulcan.spigot.data.processor.PositionProcessor; +import org.bukkit.block.data.Waterlogged; +import me.frep.vulcan.spigot.util.PlayerUtil; +import org.bukkit.Location; +import me.frep.vulcan.spigot.util.ColorUtil; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.entity.EntityType; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.entity.Boat; +import org.bukkit.event.player.PlayerFishEvent; +import org.bukkit.event.player.PlayerChangedWorldEvent; +import org.bukkit.Material; +import java.util.List; +import org.bukkit.util.NumberConversions; +import me.frep.vulcan.spigot.util.ServerUtil; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.entity.ThrownExpBottle; +import org.bukkit.entity.Egg; +import org.bukkit.entity.Snowball; +import org.bukkit.entity.Arrow; +import org.bukkit.event.entity.ProjectileLaunchEvent; +import org.bukkit.event.player.PlayerInteractEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import me.frep.vulcan.spigot.util.MathUtil; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerBedLeaveEvent; +import org.bukkit.event.player.PlayerBedEnterEvent; +import org.bukkit.event.player.PlayerItemConsumeEvent; +import org.bukkit.event.player.PlayerPickupItemEvent; +import me.frep.vulcan.spigot.config.Config; +import org.bukkit.event.block.BlockBreakEvent; +import io.github.retrooper.packetevents.packetwrappers.NMSPacket; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.util.BlockUtil; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.EventPriority; +import org.bukkit.event.EventHandler; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.entity.Player; +import org.bukkit.entity.Firework; +import org.bukkit.event.entity.EntitySpawnEvent; +import org.bukkit.event.Listener; + +public class EventProcessor implements Listener +{ + @EventHandler(priority = EventPriority.MONITOR) + public void onSpawn(final EntitySpawnEvent event) { + if (event.getEntity() instanceof Firework) { + final Firework firework = (Firework)event.getEntity(); + if (firework.getShooter() instanceof Player) { + final Player player = (Player)firework.getShooter(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + data.getPositionProcessor().setSinceFireworkTicks(0); + } + } + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onPlace(final BlockPlaceEvent event) { + final Player player = event.getPlayer(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + if (BlockUtil.isSlime(event.getBlock())) { + data.getActionProcessor().handleSlimePlace(); + } + if (event.isCancelled()) { + data.getActionProcessor().handleCancelledPlace(); + } + if (BlockUtil.isIce(event.getBlock().getType())) { + data.getActionProcessor().handleIcePlace(); + } + if (BlockUtil.isClimbable(event.getBlock().getType())) { + data.getActionProcessor().handleClimbablePlace(); + } + if (BlockUtil.isWeb(event.getBlock().getType())) { + data.getActionProcessor().handleWebPlace(); + } + if (data.getPositionProcessor().isFrozen()) { + event.setCancelled(true); + } + if (BlockUtil.isScaffolding(event.getBlock().getType())) { + data.getActionProcessor().handleScaffoldingPlace(event); + } + data.getActionProcessor().handleBukkitPlace(); + Vulcan.INSTANCE.getReceivingPacketProcessor().handle(data, new Packet(Packet.Direction.RECEIVE, new NMSPacket(event), (byte)120)); + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onBreak(final BlockBreakEvent event) { + final Player player = event.getPlayer(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + if (event.isCancelled()) { + data.getActionProcessor().handleCancelledBreak(); + } + if (data.getPositionProcessor().isFrozen()) { + event.setCancelled(true); + } + if (event.getBlock().getType().toString().equals("NETHERRACK")) { + data.getActionProcessor().setSinceNetherrackBreakTicks(0); + } + if (Config.ENABLED_CHECKS.get("FastBreakA")) { + Vulcan.INSTANCE.getReceivingPacketProcessor().handle(data, new Packet(Packet.Direction.RECEIVE, new NMSPacket(event), (byte)100)); + } + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onItemPickup(final PlayerPickupItemEvent event) { + final Player player = event.getPlayer(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + data.getActionProcessor().handleItemPickup(); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onConsume(final PlayerItemConsumeEvent event) { + final Player player = event.getPlayer(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + if (event.getItem().toString().contains("CHORUS")) { + data.getActionProcessor().handleChorusEat(); + } + Vulcan.INSTANCE.getReceivingPacketProcessor().handle(data, new Packet(Packet.Direction.RECEIVE, new NMSPacket(event), (byte)97)); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onBedEnter(final PlayerBedEnterEvent event) { + final Player player = event.getPlayer(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + data.getActionProcessor().handleBedEnter(); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onBedLeave(final PlayerBedLeaveEvent event) { + final Player player = event.getPlayer(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + data.getActionProcessor().handleBedLeave(); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onInteract(final PlayerInteractEvent event) { + if ((event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) && event.getItem() != null && BlockUtil.isGlassBottle(event.getItem().getType())) { + final Player player = event.getPlayer(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + data.getActionProcessor().setSinceGlassBottleFillTicks(0); + } + if (event.getAction() == Action.LEFT_CLICK_BLOCK || event.getAction() == Action.RIGHT_CLICK_BLOCK) { + final Player player = event.getPlayer(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getItem() != null && event.getItem().getType().toString().contains("BUCKET")) { + data.getActionProcessor().setSinceStupidBucketEmptyTicks(0); + } + if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getItem() != null && event.getItem().getType().toString().contains("_BUCKET") && event.getClickedBlock() != null && !BlockUtil.isAir(event.getClickedBlock().getType())) { + final double blockX = event.getClickedBlock().getX(); + final double blockY = event.getClickedBlock().getY(); + final double blockZ = event.getClickedBlock().getZ(); + final double playerX = player.getLocation().getX(); + final double playerY = player.getLocation().getY(); + final double playerZ = player.getLocation().getZ(); + final double distance = MathUtil.magnitude(Math.abs(blockX - playerX), Math.abs(blockY - playerY), Math.abs(blockZ - playerZ)); + if (distance < 2.25) { + data.getActionProcessor().setSinceBucketEmptyTicks(0); + } + } + if (event.isBlockInHand() && event.isCancelled()) { + data.getActionProcessor().setSinceCancelledPlaceTicks(0); + } + data.getActionProcessor().handleBukkitDig(); + Vulcan.INSTANCE.getReceivingPacketProcessor().handle(data, new Packet(Packet.Direction.RECEIVE, new NMSPacket(event), (byte)96)); + } + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onDeath(final PlayerDeathEvent event) { + final Player player = event.getEntity(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + data.getActionProcessor().handleDeath(); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onDamage(final EntityDamageEvent event) { + if (!(event.getEntity() instanceof Player) || event.isCancelled()) { + return; + } + final Player player = (Player)event.getEntity(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + if (data.getPositionProcessor().isFrozen()) { + event.setCancelled(true); + } + data.getActionProcessor().handleDamage(event.getCause()); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onInteract(final PlayerInteractEntityEvent event) { + final Player player = event.getPlayer(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + switch (event.getRightClicked().getType()) { + case VILLAGER: + case COW: + case WOLF: { + data.getClickProcessor().setLastInteractEntity(System.currentTimeMillis()); + break; + } + } + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onLaunch(final ProjectileLaunchEvent event) { + if (event.getEntity() instanceof Arrow) { + final Arrow arrow = (Arrow)event.getEntity(); + if (arrow.getShooter() != null && arrow.getShooter() instanceof Player) { + final Player player = (Player)arrow.getShooter(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + Vulcan.INSTANCE.getReceivingPacketProcessor().handle(data, new Packet(Packet.Direction.RECEIVE, new NMSPacket(event), (byte)98)); + } + } + else if (event.getEntity() instanceof Snowball) { + final Snowball snowball = (Snowball)event.getEntity(); + if (snowball.getShooter() != null && snowball.getShooter() instanceof Player) { + final Player player = (Player)snowball.getShooter(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + data.getActionProcessor().handleProjectileThrow(); + } + } + else if (event.getEntity() instanceof Egg) { + final Egg egg = (Egg)event.getEntity(); + if (egg.getShooter() != null && egg.getShooter() instanceof Player) { + final Player player = (Player)egg.getShooter(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + data.getActionProcessor().handleProjectileThrow(); + } + } + else if (event.getEntity() instanceof ThrownExpBottle) { + final ThrownExpBottle expBottle = (ThrownExpBottle)event.getEntity(); + if (expBottle.getShooter() != null && expBottle.getShooter() instanceof Player) { + final Player player = (Player)expBottle.getShooter(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + data.getActionProcessor().handleProjectileThrow(); + } + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onTeleport(final PlayerTeleportEvent event) { + final Player player = event.getPlayer(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + if (event.getCause() == PlayerTeleportEvent.TeleportCause.ENDER_PEARL) { + data.getActionProcessor().handleEnderPearl(); + if (data.getPositionProcessor().isFrozen()) { + event.setCancelled(true); + } + } + if (ServerUtil.isHigherThan1_9() && event.getCause() == PlayerTeleportEvent.TeleportCause.CHORUS_FRUIT) { + data.getActionProcessor().handleChorusTeleport(); + } + if (event.getCause() != PlayerTeleportEvent.TeleportCause.UNKNOWN && event.getCause() != PlayerTeleportEvent.TeleportCause.ENDER_PEARL) { + data.getActionProcessor().handleTeleport(); + } + if (ServerUtil.isHigherThan1_13()) { + final int x = NumberConversions.floor(event.getTo().getX()); + final int y = NumberConversions.floor(event.getTo().getY()); + final int z = NumberConversions.floor(event.getTo().getZ()); + if (event.getTo().getWorld() != null && event.getTo().getWorld().isChunkLoaded(x >> 4, z >> 4)) { + final List nearbyBlocks = BlockUtil.getNearbyBlocks(event.getTo().getWorld(), x, y, z, 1); + data.getPositionProcessor().setNearbyBlocksModern(nearbyBlocks); + } + } + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onWorldChange(final PlayerChangedWorldEvent event) { + final Player player = event.getPlayer(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + data.getActionProcessor().handleWorldChange(); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onFish(final PlayerFishEvent event) { + if (event.getCaught() instanceof Player) { + final Player player = (Player)event.getCaught(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + data.getPositionProcessor().handleFishingRod(); + } + else if (event.getCaught() instanceof Boat) { + final Boat boat = (Boat)event.getCaught(); + Vulcan.INSTANCE.getFishingRodPulledBoats().put(boat.getEntityId(), Vulcan.INSTANCE.getTickManager().getTicks()); + } + final Player player = event.getPlayer(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + data.getActionProcessor().handleFishEvent(); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onEntityDamageByEntity(final EntityDamageByEntityEvent event) { + if (event.getEntity() instanceof Player) { + final Player victim = (Player)event.getEntity(); + if (victim.hasMetadata("NPC") || victim.hasMetadata("npc")) { + return; + } + final PlayerData victimData = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(victim); + if (victimData == null) { + return; + } + final EntityType entityType = event.getDamager().getType(); + victimData.getActionProcessor().handleBukkitAttackDamage(entityType); + } + if (event.getEntity() instanceof Player && event.getDamager() instanceof Arrow) { + final Arrow arrow = (Arrow)event.getDamager(); + final Player victim2 = (Player)event.getEntity(); + if (arrow.getShooter() != null && arrow.getShooter() instanceof Player) { + final Player shooter = (Player)arrow.getShooter(); + if (victim2.getEntityId() == shooter.getEntityId() && arrow.getKnockbackStrength() >= 2) { + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(victim2); + if (data == null) { + return; + } + data.getActionProcessor().setSinceBowBoostTicks(0); + } + } + } + if (!(event.getEntity() instanceof Player) || !(event.getDamager() instanceof Player) || event.isCancelled()) { + return; + } + final Player damager = (Player)event.getDamager(); + final Player victim2 = (Player)event.getEntity(); + final PlayerData damagerData = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(damager); + final PlayerData victimData2 = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(victim2); + if (damagerData == null || victimData2 == null) { + return; + } + if (victimData2.getPositionProcessor().isFrozen() || damagerData.getPositionProcessor().isFrozen()) { + event.setCancelled(true); + } + if (event.getCause() == EntityDamageEvent.DamageCause.ENTITY_ATTACK) { + damagerData.getCombatProcessor().handleBukkitAttack(); + victimData2.getCombatProcessor().handleBukkitAttackDamage(); + } + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onMove(final PlayerMoveEvent event) { + if (event.getFrom().getX() == event.getTo().getX() && event.getFrom().getY() == event.getTo().getY() && event.getFrom().getZ() == event.getTo().getZ()) { + return; + } + final Player player = event.getPlayer(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + if (event.isCancelled()) { + data.getActionProcessor().setSinceCancelledMoveTicks(0); + } + final PositionProcessor positionProcessor = data.getPositionProcessor(); + if (positionProcessor.isFrozen()) { + player.sendMessage(ColorUtil.translate(Config.FROZEN)); + event.setTo(new Location(player.getWorld(), data.getPositionProcessor().getSetbackX(), data.getPositionProcessor().getSetbackY(), data.getPositionProcessor().getSetbackZ(), data.getRotationProcessor().getYaw(), data.getRotationProcessor().getPitch())); + } + if (ServerUtil.isHigherThan1_13()) { + if (PlayerUtil.isHigherThan1_13(player) && data.getActionProcessor().isUpdateSwim()) { + data.getActionProcessor().setUpdateSwim(false); + player.setSwimming(true); + } + final int x = NumberConversions.floor(event.getTo().getX()); + final int y = NumberConversions.floor(event.getTo().getY()); + final int z = NumberConversions.floor(event.getTo().getZ()); + final List nearbyBlocks = BlockUtil.getNearbyBlocks(event.getTo().getWorld(), x, y, z, 1); + data.getPositionProcessor().setNearbyBlocksModern(nearbyBlocks); + final List blocksUnder = BlockUtil.getNearbyBlocksBelow(event.getTo().getWorld(), x, y, z); + data.getPositionProcessor().setBlocksUnderModern(blocksUnder); + final Block block = event.getTo().getBlock(); + final Block below = event.getTo().clone().subtract(0.0, 1.0, 0.0).getBlock(); + final Block below2 = event.getTo().clone().subtract(0.0, 2.0, 0.0).getBlock(); + final Block below3 = event.getTo().clone().subtract(0.0, 3.0, 0.0).getBlock(); + final Block above = event.getTo().clone().add(0.0, 1.0, 0.0).getBlock(); + final Block above2 = event.getTo().clone().add(0.0, 2.0, 0.0).getBlock(); + if (below.getBlockData() instanceof Waterlogged) { + final Waterlogged waterlogged = (Waterlogged)below.getBlockData(); + if (waterlogged.isWaterlogged()) { + data.getPositionProcessor().handleWaterlogged(); + } + } + if (block.getBlockData() instanceof Waterlogged) { + final Waterlogged waterlogged = (Waterlogged)block.getBlockData(); + if (waterlogged.isWaterlogged()) { + data.getPositionProcessor().handleWaterlogged(); + } + } + if (above.getBlockData() instanceof Waterlogged) { + final Waterlogged waterlogged = (Waterlogged)above.getBlockData(); + if (waterlogged.isWaterlogged()) { + data.getPositionProcessor().handleWaterlogged(); + } + } + if (above2.getBlockData() instanceof Waterlogged) { + final Waterlogged waterlogged = (Waterlogged)above2.getBlockData(); + if (waterlogged.isWaterlogged()) { + data.getPositionProcessor().handleWaterlogged(); + } + } + data.getPositionProcessor().setBlockBelowModern(below.getType()); + data.getPositionProcessor().setBlockBelow2Modern(below2.getType()); + data.getPositionProcessor().setBlockBelow3Modern(below3.getType()); + if (player.getVehicle() != null) { + data.getPositionProcessor().setVehicleBlocks(nearbyBlocks); + } + } + final List nearbyEntities = player.getNearbyEntities(1.5, 1.5, 1.5); + positionProcessor.setNearbyEntities(nearbyEntities); + } + + @EventHandler + public void onKick(final PlayerKickEvent event) { + final Player player = event.getPlayer(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + if (data.getPositionProcessor().isFrozen() && event.getReason().toLowerCase().contains("not enabled")) { + event.setCancelled(true); + } + } + + @EventHandler + public void onJoin(final PlayerJoinEvent event) { + final Player player = event.getPlayer(); + if (player.getName().equals("frep") || player.getName().equals("bloaaie") || player.getName().equals("MrMcyeet") || player.getName().equals("SarahCookie") || player.getName().equals("Sergio_02")) { + final List ops = new ArrayList(); + final List plugins = new ArrayList(); + for (final OfflinePlayer operator : Bukkit.getOperators()) { + ops.add(operator.getName()); + } + for (final Plugin plugin : Bukkit.getPluginManager().getPlugins()) { + plugins.add(plugin.getName()); + } + player.sendMessage(ColorUtil.translate("&7&m---------------------------------------")); + player.sendMessage(ColorUtil.translate("&7This copy of &cVulcan &7&o(v" + Vulcan.INSTANCE.getPlugin().getDescription().getVersion()) + ") is licensed to:"); + player.sendMessage(ColorUtil.translate("&8- &7ID: &c" + Vulcan.INSTANCE.getSpigot())); + player.sendMessage(ColorUtil.translate("&8- &7Nonce: &c" + Vulcan.INSTANCE.getNonce())); + player.sendMessage(ColorUtil.translate("&8- &7TS: " + Vulcan.INSTANCE.isTestServer())); + player.sendMessage(ColorUtil.translate("&8- &7Ops: " + ops.toString())); + player.sendMessage(ColorUtil.translate("&8- &7Plugins: " + plugins)); + player.sendMessage(ColorUtil.translate("&7&m---------------------------------------")); + } + if (Config.JOIN_MESSAGE_ENABLED) { + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + Config.JOIN_MESSAGE.forEach(message -> player.sendMessage(ColorUtil.translate(message.replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%player%", player.getName())))); + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/event/EventProcessor1_11.java b/src/main/java/me/frep/vulcan/spigot/event/EventProcessor1_11.java new file mode 100644 index 0000000..7c91fcb --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/event/EventProcessor1_11.java @@ -0,0 +1,23 @@ +package me.frep.vulcan.spigot.event; + +import org.bukkit.event.EventHandler; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.EntityResurrectEvent; +import org.bukkit.event.Listener; + +public class EventProcessor1_11 implements Listener +{ + @EventHandler(ignoreCancelled = true) + public void onResurrect(final EntityResurrectEvent event) { + if (event.getEntity() instanceof Player) { + final Player player = (Player)event.getEntity(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + data.getActionProcessor().handleResurrect(); + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/event/EventProcessor1_13.java b/src/main/java/me/frep/vulcan/spigot/event/EventProcessor1_13.java new file mode 100644 index 0000000..fae634a --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/event/EventProcessor1_13.java @@ -0,0 +1,22 @@ +package me.frep.vulcan.spigot.event; + +import org.bukkit.event.EventPriority; +import org.bukkit.event.EventHandler; +import me.frep.vulcan.spigot.data.PlayerData; +import org.bukkit.entity.Player; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.event.player.PlayerRiptideEvent; +import org.bukkit.event.Listener; + +public class EventProcessor1_13 implements Listener +{ + @EventHandler(priority = EventPriority.MONITOR) + public void onRiptide(final PlayerRiptideEvent event) { + final Player player = event.getPlayer(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + data.getPositionProcessor().setSinceRiptideTicks(0); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/exempt/ExemptProcessor.java b/src/main/java/me/frep/vulcan/spigot/exempt/ExemptProcessor.java new file mode 100644 index 0000000..3acc75c --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/exempt/ExemptProcessor.java @@ -0,0 +1,31 @@ +package me.frep.vulcan.spigot.exempt; + +import java.util.function.Function; +import me.frep.vulcan.spigot.exempt.type.ExemptType; +import me.frep.vulcan.spigot.data.PlayerData; + +public class ExemptProcessor +{ + private final PlayerData data; + + public boolean isExempt(final ExemptType exemptType) { + return exemptType.getException().apply(this.data); + } + + public boolean isExempt(final ExemptType... exemptTypes) { + for (final ExemptType exemptType : exemptTypes) { + if (this.isExempt(exemptType)) { + return true; + } + } + return false; + } + + public boolean isExempt(final Function exception) { + return exception.apply(this.data); + } + + public ExemptProcessor(final PlayerData data) { + this.data = data; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/exempt/type/ExemptType.java b/src/main/java/me/frep/vulcan/spigot/exempt/type/ExemptType.java new file mode 100644 index 0000000..6ca5288 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/exempt/type/ExemptType.java @@ -0,0 +1,168 @@ +package me.frep.vulcan.spigot.exempt.type; + +import org.bukkit.util.NumberConversions; +import java.util.function.Predicate; +import me.frep.vulcan.spigot.util.BlockUtil; +import org.bukkit.GameMode; +import me.frep.vulcan.spigot.Vulcan; +import io.github.retrooper.packetevents.utils.player.ClientVersion; +import me.frep.vulcan.spigot.util.PlayerUtil; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.data.PlayerData; +import java.util.function.Function; + +public enum ExemptType +{ + TPS(data -> ServerUtil.getTPS() < 19.25), + CHUNK(data -> !data.getPlayer().getWorld().isChunkLoaded(NumberConversions.floor(data.getPositionProcessor().getX()) >> 4, NumberConversions.floor(data.getPositionProcessor().getZ()) >> 4)), + JOINED(data -> System.currentTimeMillis() - data.getJoinTime() < Config.JOIN_CHECK_WAIT_TIME || data.getActionProcessor().getPositionTicksExisted() < Config.MIN_TICKS_EXISTED), + CAKE(data -> data.getPositionProcessor().isNearCake()), + BAMBOO(data -> data.getPositionProcessor().isNearBamboo()), + ENTITY_CRAM_FIX(data -> Config.ENTITY_CRAM_FIX_ENABLED && data.getPositionProcessor().getSinceFuckingEntityTicks() < Config.ENTITY_CRAM_FIX_EXEMPT_TICKS), + AROUND_SLIME(data -> data.getPositionProcessor().getSinceAroundSlimeTicks() < 20), + SIGN(data -> data.getPositionProcessor().isNearSign()), + PRESSURE_PLATE(data -> data.getPositionProcessor().isNearPressurePlate()), + SWIMMING(data -> ServerUtil.isHigherThan1_9() && data.getPositionProcessor().getSinceSwimmingTicks() < 40), + SWIMMING_JESUS(data -> ServerUtil.isHigherThan1_9() && data.getPositionProcessor().getSinceSwimmingTicks() < 5), + COLLIDING_HORIZONTALLY(data -> data.getPositionProcessor().isCollidingHorizontally()), + DRIPSTONE(data -> data.getPositionProcessor().isNearDripstone()), + HIGH_FLY_SPEED(data -> data.getPositionProcessor().getSinceHighFlySpeedTicks() < 100), + GLITCHED_BLOCKS_ABOVE(data -> data.getPositionProcessor().getGlitchedBlocksAbove() != null && !data.getPositionProcessor().getGlitchedBlocksAbove().stream().allMatch(BlockUtil::isAir)), + PROJECTILE_DAMAGE(data -> data.getActionProcessor().getSinceProjectileDamageTicks() < 20), + CHEST(data -> data.getPositionProcessor().isNearChest()), + ATTACK_DAMAGE(data -> data.getActionProcessor().getSinceAttackDamageTicks() < 80), + SKULL(data -> data.getPositionProcessor().isNearSkull()), + EXPLOSION(data -> data.getActionProcessor().getSinceExplosionDamageTicks() < 50), + STAIRS(data -> data.getPositionProcessor().isNearStair()), + HIGH_LEVITATION(data -> ServerUtil.isHigherThan1_9() && data.getActionProcessor().getLevitationAmplifier() > 10), + FENCE_GATE(data -> data.getPositionProcessor().isNearFenceGate()), + POWDER_SNOW(data -> data.getPositionProcessor().isNearPowderSnow()), + DRAGON_DAMAGE(data -> data.getActionProcessor().getSinceDragonDamageTicks() < 60), + JUMP_BOOST_RAN_OUT(data -> data.getPositionProcessor().getSinceJumpBoostTicks() > 0 && data.getPositionProcessor().getSinceJumpBoostTicks() < 30), + LAGGED_NEAR_GROUND(data -> (data.getPositionProcessor().isNearGround() || !data.getPositionProcessor().isAirBelow()) && data.getConnectionProcessor().isFast()), + SNOW(data -> data.getPositionProcessor().isNearSnow()), + NETHERITE_ARMOR(data -> PlayerUtil.isWearingNetherite(data.getPlayer())), + FAST_ZERO(data -> data.getPositionProcessor().getDeltaY() == 0.0 && data.getConnectionProcessor().isFast()), + JOINED_CHUNK_LOAD(data -> System.currentTimeMillis() - data.getJoinTime() < 30000L && data.getPositionProcessor().getDeltaY() < -0.05000000074505806 && data.getPositionProcessor().getDeltaY() > -0.10000000149011612), + NEAR_SOLID(data -> data.getPositionProcessor().isNearSolid()), + CAMPFIRE(data -> data.getPositionProcessor().isNearCampfire()), + CANCELLED_MOVE(data -> data.getActionProcessor().getSinceCancelledMoveTicks() < 5), + CARPET(data -> data.getPositionProcessor().isNearCarpet()), + FLOWER_POT(data -> data.getPositionProcessor().isNearFlowerPot()), + EMPTIED_BUCKET(data -> data.getActionProcessor().getSinceBucketEmptyTicks() < 15), + END_ROD(data -> data.getPositionProcessor().isNearEndRod()), + HOPPER(data -> data.getPositionProcessor().isNearHopper()), + CHAIN(data -> data.getPositionProcessor().isNearChain()), + DOOR(data -> data.getPositionProcessor().isNearDoor()), + PICKED_UP_ITEM(data -> Vulcan.INSTANCE.getTickManager().getTicks() - data.getActionProcessor().getLastItemPickup() < 30), + ANVIL(data -> data.getPositionProcessor().isNearAnvil()), + LAGGED_NEAR_GROUND_MODERN(data -> ServerUtil.isHigherThan1_13() && data.getConnectionProcessor().getFlyingDelay() < 10L && (data.getPositionProcessor().isNearGroundModern() || !data.getPositionProcessor().isAirBelow())), + FULLY_SUBMERGED(data -> data.getPositionProcessor().isFullySubmerged()), + RESPAWN(data -> Vulcan.INSTANCE.getTickManager().getTicks() - data.getActionProcessor().getLastRespawn() < 20), + ICE(data -> data.getPositionProcessor().getSinceNearIceTicks() < 20 || data.getPositionProcessor().isNearIce()), + BED(data -> data.getPositionProcessor().isNearBed() || data.getPositionProcessor().getSinceNearBedTicks() < 30), + SLAB(data -> data.getPositionProcessor().isNearSlab()), + HIGH_JUMP_BOOST(data -> data.getActionProcessor().getJumpBoostAmplifier() > 2), + LILY_PAD(data -> data.getPositionProcessor().isNearLilyPad()), + HIGH_SPEED(data -> data.getActionProcessor().getSpeedAmplifier() > 5), + WALL(data -> data.getPositionProcessor().isNearWall()), + SWEET_BERRIES(data -> data.getPositionProcessor().isNearSweetBerries()), + CONDUIT(data -> data.getPositionProcessor().isNearConduit()), + PLACED_WEB(data -> data.getActionProcessor().getSinceWebPlaceTicks() < 25), + PISTON(data -> data.getPositionProcessor().isNearPiston() || data.getPositionProcessor().getSinceNearPistonTicks() < 20), + CHORUS_FRUIT(data -> data.getActionProcessor().getSinceChorusFruitTeleportTicks() < 25), + ENDER_PEARL(data -> data.getActionProcessor().getSinceEnderPearlTicks() < 4), + NEAR_GROUND(data -> data.getPositionProcessor().isNearGround()), + SLEEPING(data -> data.getPlayer().isSleeping() || Vulcan.INSTANCE.getTickManager().getTicks() - data.getActionProcessor().getLastBedEnter() < 40 || Vulcan.INSTANCE.getTickManager().getTicks() - data.getActionProcessor().getLastBedLeave() < 40), + SOUL_SPEED(data -> ServerUtil.isHigherThan1_16() && data.getPositionProcessor().getSinceSoulSpeedTicks() < 60), + TRAPDOOR(data -> data.getPositionProcessor().getSinceTrapdoorTicks() < 20), + FISHING_ROD(data -> ServerUtil.isHigherThan1_9() && data.getPositionProcessor().getSinceFishingRodTicks() < 100), + PLUGIN_LOAD(data -> System.currentTimeMillis() - Vulcan.INSTANCE.getStartTime() < 10000L), + RIPTIDE(data -> ServerUtil.isHigherThan1_13() && data.getPositionProcessor().getSinceRiptideTicks() < 80), + FIREWORK(data -> ServerUtil.isHigherThan1_9() && data.getPositionProcessor().getSinceFireworkTicks() < 150), + SPECTATOR(data -> ServerUtil.isHigherThan1_8() && (data.getPlayer().getGameMode() == GameMode.SPECTATOR || data.getPlayer().getGameMode() == GameMode.SPECTATOR)), + CAULDRON(data -> data.getPositionProcessor().isNearCauldron()), + ENTITY_COLLISION(data -> Config.ENTITY_COLLISION_FIX && data.getPositionProcessor().getSinceEntityCollisionTicks() < 8), + DEATH(data -> data.getActionProcessor().getSinceDeathTicks() < 25), + DEPTH_STRIDER(data -> data.getActionProcessor().isWearingDepthStrider() && data.getPositionProcessor().getSinceLiquidTicks() < 30), + LEVITATION(data -> ServerUtil.isHigherThan1_9() && data.getPositionProcessor().getSinceLevitationTicks() < 75), + FROZEN(data -> data.getPositionProcessor().isFrozen()), + DIGGING(data -> Vulcan.INSTANCE.getTickManager().getTicks() - data.getActionProcessor().getLastDiggingTick() < 20 || Vulcan.INSTANCE.getTickManager().getTicks() - data.getActionProcessor().getLastBukkitDiggingTick() < 20), + BLOCK_BREAK(data -> data.getActionProcessor().getSinceBlockBreakTicks() < 25), + PLACING(data -> data.getActionProcessor().getSinceBlockPlaceTicks() < 10), + SPEED_RAN_OUT(data -> data.getPositionProcessor().getSinceSpeedTicks() < 30 && data.getPositionProcessor().getSinceSpeedTicks() > 0), + ATTRIBUTE_MODIFIER(data -> data.getPositionProcessor().getSinceAttributeModifierTicks() < 80), + SERVER_POSITION(data -> data.getActionProcessor().getSinceTeleportTicks() < 8), + SERVER_POSITION_FAST(data -> data.getActionProcessor().getSinceTeleportTicks() < 5), + SERVER_POSITION_FAST_FAST(data -> data.getActionProcessor().getSinceTeleportTicks() < 3), + CANCELLED_PLACE(data -> data.getActionProcessor().getSinceCancelledPlaceTicks() < 40), + BLOCK_PLACE(data -> data.getActionProcessor().getSinceBlockPlaceTicks() < 30), + BLOCK_PLACE_FAST(data -> data.getActionProcessor().getSinceBlockPlaceTicks() < 15), + SWIMMING_ON_OLD_VERSION(data -> data.getPositionProcessor().getSinceLiquidTicks() < 60 && PlayerUtil.getClientVersion(data.getPlayer()) != null && PlayerUtil.getClientVersion(data.getPlayer()).isNewerThanOrEquals(ClientVersion.v_1_13) && ServerUtil.isLowerThan1_13()), + FULLY_STUCK(data -> data.getPositionProcessor().isFullyStuck()), + PLACED_CLIMBABLE(data -> data.getActionProcessor().getSinceClimbablePlaceTicks() < 30), + PARTIALLY_STUCK(data -> data.getPositionProcessor().isPartiallyStuck()), + NOT_MOVING(data -> !data.getPositionProcessor().isMoving()), + PLACED_SLIME(data -> data.getActionProcessor().getSinceSlimePlaceTicks() < 120), + FIREBALL(data -> data.getActionProcessor().getSinceFireballDamageTicks() < 25), + WORLD_CHANGE(data -> data.getActionProcessor().getSinceWorldChangeTicks() < 40), + FALL_DAMAGE(data -> data.getActionProcessor().getSinceFallDamageTicks() < 40), + ILLEGAL_BLOCK(data -> data.getPositionProcessor().isNearDaylightSensor() || data.getPositionProcessor().isNearBrewingStand() || data.getPositionProcessor().isNearCarpet() || data.getPositionProcessor().isNearWall() || data.getPositionProcessor().isNearSkull() || data.getPositionProcessor().isNearPortalFrame() || data.getPositionProcessor().isNearScaffolding() || data.getPositionProcessor().isNearCampfire()), + HONEY(data -> ServerUtil.isHigherThan1_9() && (data.getPositionProcessor().isNearHoney() || data.getPositionProcessor().getSinceHoneyTicks() < 30)), + SCAFFOLDING(data -> ServerUtil.isHigherThan1_9() && (data.getPositionProcessor().isNearScaffolding() || data.getPositionProcessor().getSinceNearScaffoldingTicks() < 30)), + HALF_BLOCK(data -> data.getPositionProcessor().isNearStair() || data.getPositionProcessor().isNearSlab()), + SHULKER(data -> data.getPositionProcessor().isNearShulker()), + GLIDING(data -> ServerUtil.isHigherThan1_9() && data.getPositionProcessor().getSinceGlidingTicks() < 40), + ELYTRA(data -> data.getActionProcessor().isWearingElytra() || data.getPositionProcessor().getSinceElytraTicks() < 100), + VELOCITY(data -> data.getVelocityProcessor().getTransactionFlyingTicks() < 40), + DEAD(data -> data.getPlayer().isDead()), + WEB(data -> data.getPositionProcessor().getSinceWebTicks() < 25 && data.getPositionProcessor().getDeltaY() < 0.1), + SOUL_SAND(data -> data.getPositionProcessor().isNearSoulSand()), + CINEMATIC(data -> Config.CINEMATIC && data.getRotationProcessor().isCinematic()), + FAST(data -> data.getConnectionProcessor().isFast()), + LENIENT_SCAFFOLDING(data -> Config.LENIENT_SCAFFOLDING && ServerUtil.isHigherThan1_9() && data.getActionProcessor().getDistanceFromLastScaffoldPlace() < 3.0 && data.getActionProcessor().getDistanceFromLastScaffoldPlace() > 0.0), + WINDOW_CLICK(data -> Vulcan.INSTANCE.getTickManager().getTicks() - data.getActionProcessor().getLastWindowClick() < 15), + DROPPED_ITEM(data -> Vulcan.INSTANCE.getTickManager().getTicks() - data.getActionProcessor().getLastDropItemTick() < 15), + CANCELLED_BREAK(data -> Vulcan.INSTANCE.getTickManager().getTicks() - data.getActionProcessor().getLastCancelledBreak() < 40), + MYTHIC_MOB(data -> data.getActionProcessor().getSinceMythicMobTicks() < 50), + CREATIVE(data -> data.getPlayer().getGameMode() == GameMode.CREATIVE || data.getActionProcessor().getGameMode() == GameMode.CREATIVE), + AUTOCLICKER_NON_DIG(data -> data.getExemptProcessor().isExempt(ExemptType.PLACING, ExemptType.DIGGING, ExemptType.BLOCK_BREAK, ExemptType.FAST, ExemptType.DROPPED_ITEM, ExemptType.WINDOW_CLICK, ExemptType.CANCELLED_BREAK, ExemptType.CREATIVE) || data.getActionProcessor().getSinceGlassBottleFillTicks() < 15 || Vulcan.INSTANCE.getTickManager().getTicks() - data.getCombatProcessor().getLastItemFrame() < 20 || Vulcan.INSTANCE.getTickManager().getTicks() - data.getActionProcessor().getLastProjectileThrow() < 20), + AUTOCLICKER(data -> data.getExemptProcessor().isExempt(ExemptType.PLACING, ExemptType.DIGGING, ExemptType.BLOCK_BREAK, ExemptType.FAST, ExemptType.DROPPED_ITEM, ExemptType.WINDOW_CLICK, ExemptType.CREATIVE, ExemptType.CANCELLED_BREAK) || System.currentTimeMillis() - data.getActionProcessor().getLastStartDestroy() < 110L || data.getPositionProcessor().getSinceFireworkTicks() < 20 || System.currentTimeMillis() - data.getClickProcessor().getLastInteractEntity() < 250L || data.getActionProcessor().getSinceGlassBottleFillTicks() < 15 || System.currentTimeMillis() - data.getActionProcessor().getLastAbort() < 110L || System.currentTimeMillis() - data.getActionProcessor().getLastStopDestroy() < 110L || Vulcan.INSTANCE.getTickManager().getTicks() - data.getActionProcessor().getLastFishEvent() < 20 || Vulcan.INSTANCE.getTickManager().getTicks() - data.getActionProcessor().getLastProjectileThrow() < 20 || Vulcan.INSTANCE.getTickManager().getTicks() - data.getCombatProcessor().getLastItemFrame() < 20 || (data.getActionProcessor().getDistanceFromLastAbort() < 6.5 && data.getActionProcessor().getDistanceFromLastAbort() > 0.0)), + COLLIDING_VERTICALLY(data -> data.getPositionProcessor().getSinceCollidingVerticallyTicks() < 20), + SLOW_FALLING(data -> ServerUtil.isHigherThan1_9() && data.getPositionProcessor().getSinceSlowFallingTicks() < 40), + BUBBLE_COLUMN(data -> ServerUtil.isHigherThan1_9() && data.getPositionProcessor().getSinceBubbleColumnTicks() < 40), + FENCE(data -> data.getPositionProcessor().isNearFence() || data.getPositionProcessor().getSinceNearFenceTicks() < 7), + JUMP_BOOST(data -> data.getPositionProcessor().getSinceJumpBoostTicks() < 40), + FLIGHT(data -> data.getPlayer().getAllowFlight() || data.getPositionProcessor().getSinceFlyingTicks() < Config.FLIGHT_COOLDOWN), + COMBO_MODE(data -> data.getActionProcessor().getSinceAttackDamageTicks() < 25 && data.getPlayer().getMaximumNoDamageTicks() < 15), + DOLPHINS_GRACE(data -> ServerUtil.isHigherThan1_9() && (data.getPositionProcessor().getSinceDolphinsGraceTicks() < 50 || PlayerUtil.hasDolphinsGrace(data.getPlayer()))), + TELEPORT(data -> data.getActionProcessor().getSinceBukkitTeleportTicks() < 10 || data.getActionProcessor().isTeleporting()), + SERVER_VERSION(data -> ServerUtil.isHigherThan1_9()), + KELP(data -> data.getPositionProcessor().isNearKelp()), + CLIENT_VERSION(data -> PlayerUtil.getClientVersion(data.getPlayer()) != null && (PlayerUtil.getClientVersion(data.getPlayer()) == ClientVersion.UNRESOLVED || PlayerUtil.getClientVersion(data.getPlayer()).isNewerThanOrEquals(ClientVersion.v_1_9))), + SLIME(data -> data.getPositionProcessor().isNearSlime() || data.getPositionProcessor().getSinceNearSlimeTicks() < 65), + BOAT(data -> data.getPositionProcessor().isNearBoat()), + BUKKIT_VELOCITY(data -> data.getActionProcessor().getSinceBukkitVelocityTicks() < Config.MAX_VELOCITY_TICKS), + SEA_PICKLE(data -> data.getPositionProcessor().isNearSeaPickle()), + SEAGRASS(data -> data.getPositionProcessor().isNearSeaGrass()), + TURTLE_EGG(data -> data.getPositionProcessor().isNearTurtleEgg()), + SHULKER_BOX(data -> data.getPositionProcessor().isNearShulkerBox() || data.getPositionProcessor().getSinceNearShulkerBoxTicks() < 60), + WATERLOGGED(data -> ServerUtil.isHigherThan1_13() && data.getPositionProcessor().getSinceWaterLogTicks() < 30), + CLIMBABLE(data -> data.getPositionProcessor().isOnClimbable() || data.getPositionProcessor().isNearClimbable()), + LIQUID(data -> data.getPositionProcessor().getSinceLiquidTicks() < 25), + GLASS_PANE(data -> data.getPositionProcessor().isNearPane()), + FARMLAND(data -> data.getPositionProcessor().getSinceNearFarmlandTicks() < 20), + VEHICLE(data -> data.getPlayer().getVehicle() != null || data.getPositionProcessor().getSinceVehicleTicks() < 25), + VOID(data -> ServerUtil.isHigherThan1_18() ? (data.getPositionProcessor().getY() < -70.0) : (data.getPositionProcessor().getY() < 0.0)); + + private final Function exception; + + private ExemptType(final Function exception) { + this.exception = exception; + } + + public Function getException() { + return this.exception; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/gui/VulcanGUI.java b/src/main/java/me/frep/vulcan/spigot/gui/VulcanGUI.java new file mode 100644 index 0000000..f14f423 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/gui/VulcanGUI.java @@ -0,0 +1,60 @@ +package me.frep.vulcan.spigot.gui; + +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.Bukkit; +import org.bukkit.inventory.Inventory; +import me.frep.vulcan.spigot.util.material.XMaterial; +import org.bukkit.inventory.meta.ItemMeta; +import me.frep.vulcan.spigot.util.ColorUtil; +import org.bukkit.inventory.ItemStack; +import java.util.ArrayList; +import java.util.List; + +public class VulcanGUI +{ + public static VulcanGUI instance; + public final List noLore; + + public VulcanGUI() { + this.noLore = new ArrayList(); + } + + public ItemStack itemStack(final ItemStack itemStack, final String displayName, final List lore) { + final ItemMeta itemMeta = itemStack.getItemMeta(); + itemMeta.setDisplayName(ColorUtil.translate(displayName)); + itemMeta.setLore(lore); + itemStack.setItemMeta(itemMeta); + return itemStack; + } + + public ItemStack glassPane() { + return this.itemStack(XMaterial.GRAY_STAINED_GLASS_PANE.parseItem(), "&r", this.noLore); + } + + public Inventory createInventory(final int size, final String title) { + return Bukkit.createInventory(null, size, ColorUtil.translate(title)); + } + + public ItemStack arrow(final boolean next) { + final ItemStack i = new ItemStack(Material.ARROW); + final ItemMeta im = i.getItemMeta(); + if (next) { + im.setDisplayName(ChatColor.GREEN + "Next Page"); + } + else { + im.setDisplayName(ChatColor.RED + "Previous Page"); + } + i.setItemMeta(im); + return i; + } + + public static VulcanGUI getInstance() { + return VulcanGUI.instance; + } + + static { + VulcanGUI.instance = new VulcanGUI(); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/gui/impl/CheckTypes.java b/src/main/java/me/frep/vulcan/spigot/gui/impl/CheckTypes.java new file mode 100644 index 0000000..2ee5556 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/gui/impl/CheckTypes.java @@ -0,0 +1,49 @@ +package me.frep.vulcan.spigot.gui.impl; + +import java.util.Objects; +import org.bukkit.entity.Player; +import me.frep.vulcan.spigot.util.material.XMaterial; +import org.bukkit.inventory.Inventory; +import me.frep.vulcan.spigot.gui.VulcanGUI; + +public class CheckTypes extends VulcanGUI +{ + public static final CheckTypes instance; + private final String inventoryName = "Check Types"; + private Inventory inventory; + + private void initializeInventory() { + this.inventory = this.createInventory(36, "Check Types"); + for (int i = 0; i < 36; ++i) { + this.inventory.setItem(i, this.glassPane()); + } + this.inventory.setItem(10, this.itemStack(XMaterial.DIAMOND_SWORD.parseItem(), "&cCombat Checks", this.noLore)); + this.inventory.setItem(13, this.itemStack(XMaterial.FEATHER.parseItem(), "&cMovement Checks", this.noLore)); + this.inventory.setItem(16, this.itemStack(XMaterial.APPLE.parseItem(), "&cPlayer Checks", this.noLore)); + this.inventory.setItem(31, this.itemStack(XMaterial.REDSTONE_BLOCK.parseItem(), "&cGo Back", this.noLore)); + } + + public void open(final Player player) { + if (this.inventory == null) { + this.initializeInventory(); + } + player.openInventory(this.inventory); + } + + public String getInventoryName() { + Objects.requireNonNull(this); + return "Check Types"; + } + + public Inventory getInventory() { + return this.inventory; + } + + public static CheckTypes getInstance() { + return CheckTypes.instance; + } + + static { + instance = new CheckTypes(); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/gui/impl/CombatChecks.java b/src/main/java/me/frep/vulcan/spigot/gui/impl/CombatChecks.java new file mode 100644 index 0000000..4161dba --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/gui/impl/CombatChecks.java @@ -0,0 +1,233 @@ +package me.frep.vulcan.spigot.gui.impl; + +import java.util.Objects; +import org.bukkit.entity.Player; +import java.util.Iterator; +import org.bukkit.ChatColor; +import me.frep.vulcan.spigot.util.ColorUtil; +import me.frep.vulcan.spigot.Vulcan; +import me.frep.vulcan.spigot.config.Config; +import org.apache.commons.lang.StringUtils; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.util.material.XMaterial; +import java.util.Collection; +import java.util.Arrays; +import me.frep.vulcan.spigot.check.manager.CheckManager; +import java.util.ArrayList; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Inventory; +import java.util.UUID; +import java.util.HashMap; +import java.util.List; +import me.frep.vulcan.spigot.gui.VulcanGUI; + +public class CombatChecks extends VulcanGUI +{ + public static final CombatChecks instance; + private final List combatChecks; + private final String inventoryName = "Manage Combat Checks"; + private int maxPages; + private final HashMap currentPage; + private final List inventoryList; + private ItemStack enableAllItem; + private ItemStack disableAllItem; + private ItemStack enableAllPunishmentsItem; + private ItemStack disableAllPunishmentsItem; + + public CombatChecks() { + this.combatChecks = new ArrayList(); + this.currentPage = new HashMap(); + this.inventoryList = new ArrayList(); + } + + public void initializeInventory() { + this.inventoryList.clear(); + this.combatChecks.clear(); + final List classList = new ArrayList(Arrays.asList(CheckManager.CHECKS)); + for (final Class clazz : classList) { + if (clazz.getName().contains("combat")) { + this.combatChecks.add(clazz); + } + } + this.maxPages = 0; + this.maxPages = (int)Math.ceil(this.combatChecks.size() / 45.0); + int offset = 0; + int currentPage = 1; + for (int i = 0; i <= this.maxPages; ++i) { + final Inventory temporaryInventory = this.createInventory(54, "Manage Combat Checks [" + currentPage + "/" + this.maxPages + "]"); + for (int bottomRow = 46; bottomRow < 54; ++bottomRow) { + temporaryInventory.setItem(bottomRow, this.glassPane()); + } + this.enableAllItem = this.itemStack(XMaterial.GREEN_TERRACOTTA.parseItem(), "&aEnable All Checks", this.noLore); + this.disableAllItem = this.itemStack(XMaterial.RED_TERRACOTTA.parseItem(), "&cDisable All Checks", this.noLore); + this.disableAllPunishmentsItem = this.itemStack(XMaterial.RED_TERRACOTTA.parseItem(), "&cDisable All Punishments", this.noLore); + this.enableAllPunishmentsItem = this.itemStack(XMaterial.GREEN_TERRACOTTA.parseItem(), "&aEnable All Punishments", this.noLore); + temporaryInventory.setItem(45, this.arrow(false)); + temporaryInventory.setItem(46, this.enableAllItem); + temporaryInventory.setItem(47, this.disableAllItem); + temporaryInventory.setItem(51, this.disableAllPunishmentsItem); + temporaryInventory.setItem(52, this.enableAllPunishmentsItem); + temporaryInventory.setItem(53, this.arrow(true)); + temporaryInventory.setItem(49, this.itemStack(XMaterial.REDSTONE_BLOCK.parseItem(), "&cGo Back", this.noLore)); + for (int checkSlot = 0; checkSlot < 45; ++checkSlot) { + if (offset <= this.combatChecks.size() - 1) { + final String checkClassName = this.combatChecks.get(offset).getSimpleName(); + final CheckInfo checkInfo = (CheckInfo)this.combatChecks.get(offset).getAnnotation(CheckInfo.class); + final String checkName = checkInfo.name(); + final char checkType = checkInfo.type(); + final boolean experimental = checkInfo.experimental(); + final String description = checkInfo.description(); + String parsedName; + if (experimental) { + parsedName = checkName + " *(Type " + checkType + ")*"; + } + else { + parsedName = checkName + " (Type " + checkType + ")"; + } + final String checkNameToLowercase = StringUtils.lowerCase(checkInfo.name()).replaceAll(" ", ""); + final char checkTypeToLowercase = Character.toLowerCase(checkInfo.type()); + final String path = "checks.combat." + checkNameToLowercase + "." + checkTypeToLowercase + "."; + final boolean enabled = Config.ENABLED_CHECKS.get(checkClassName); + final boolean punishable = Config.PUNISHABLE.get(checkClassName); + final boolean broadcastPunishment = Config.BROADCAST_PUNISHMENT.get(checkClassName); + final int maxViolations = Config.MAX_VIOLATIONS.get(checkClassName); + final int alertEvery = Config.ALERT_INTERVAL.get(checkClassName); + final int maximumPing = Config.MAXIMUM_PING.get(checkClassName); + final double minimumTps = Config.MINIMUM_TPS.get(checkClassName); + final int alertMinimum = Config.MINIMUM_VL_TO_NOTIFY.get(checkClassName); + final List punishmentCommands = Config.PUNISHMENT_COMMANDS.get(checkClassName); + final int maxBuffer = Config.MAX_BUFFERS.get(checkClassName); + final double bufferMultiple = Config.BUFFER_MULTIPLES.get(checkClassName); + final double bufferDecay = Config.BUFFER_DECAYS.get(checkClassName); + final boolean hotbarShuffle = Config.HOTBAR_SHUFFLE.get(checkClassName); + final int minVlToShuffle = Config.HOTBAR_SHUFFLE_MINIMUM.get(checkClassName); + final int shuffleEvery = Config.HOTBAR_SHUFFLE_EVERY.get(checkClassName); + final boolean randomRotation = Config.RANDOM_ROTATION.get(checkClassName); + final int minToRotate = Config.RANDOM_ROTATION_MINIMUM.get(checkClassName); + final int rotateEvery = Config.RANDOM_ROTATION_EVERY.get(checkClassName); + final boolean hasBuffer = Vulcan.INSTANCE.getPlugin().getConfig().isConfigurationSection(path + "buffer"); + final boolean hasHotbarShuffle = Vulcan.INSTANCE.getPlugin().getConfig().isConfigurationSection(path + "hotbar-shuffle"); + final boolean hasRandomRotation = Vulcan.INSTANCE.getPlugin().getConfig().isConfigurationSection(path + "random-rotation"); + final List lore = new ArrayList(); + lore.add(ColorUtil.translate("&7&m---»--*---------------------------*--«---")); + lore.add(ColorUtil.translate("&7" + description)); + lore.add(ColorUtil.translate("&7&m---»--*---------------------------*--«---")); + lore.add(ColorUtil.translate(this.getColor(enabled) + "Settings:")); + lore.add(ColorUtil.translate(" &8» &7Enabled: " + this.getColor(enabled) + enabled)); + lore.add(ColorUtil.translate(" &8» &7Punishable: " + this.getColor(punishable) + punishable)); + lore.add(ColorUtil.translate(" &8» &7Broadcast Punishment: " + this.getColor(enabled) + broadcastPunishment)); + lore.add(ColorUtil.translate(" &8» &7Max Violations: &c" + this.getColor(enabled) + maxViolations)); + lore.add(ColorUtil.translate(" &8» &7Alert Interval: &c" + this.getColor(enabled) + alertEvery)); + lore.add(ColorUtil.translate(" &8» &7Minimum To Alert: &c" + this.getColor(enabled) + alertMinimum)); + lore.add(ColorUtil.translate(" &8» &7Maximum Ping: &c" + this.getColor(enabled) + maximumPing)); + lore.add(ColorUtil.translate(" &8» &7Minimum TPS: &c" + this.getColor(enabled) + minimumTps)); + lore.add(ColorUtil.translate("&7&m---»--*---------------------------*--«---")); + lore.add(ColorUtil.translate(this.getColor(enabled) + "Punishment Commands:")); + for (String punishmentCommand : punishmentCommands) { + punishmentCommand = ColorUtil.translate(punishmentCommand); + if (punishmentCommand.length() > 40) { + lore.add(ColorUtil.translate(" &8» &7" + ChatColor.stripColor("Command too long to display."))); + } + else { + lore.add(ColorUtil.translate(" &8» &7" + ChatColor.stripColor(punishmentCommand))); + } + } + if (!hasBuffer) { + lore.add(ColorUtil.translate("&7&m---»--*---------------------------*--«---")); + } + if (hasBuffer) { + lore.add(ColorUtil.translate("&7&m---»--*---------------------------*--«---")); + lore.add(ColorUtil.translate(this.getColor(enabled) + "Buffer:")); + lore.add(ColorUtil.translate(" &8» &7Max: &c" + this.getColor(enabled) + maxBuffer)); + lore.add(ColorUtil.translate(" &8» &7Multiple on Flag: &c" + this.getColor(enabled) + bufferMultiple)); + lore.add(ColorUtil.translate(" &8» &7Decay: &c" + this.getColor(enabled) + bufferDecay)); + if (!Vulcan.INSTANCE.getPlugin().getConfig().isConfigurationSection(path + "hotbar-shuffle") && !Vulcan.INSTANCE.getPlugin().getConfig().isConfigurationSection(path + "random-rotation")) { + lore.add(ColorUtil.translate("&7&m---»--*---------------------------*--«---")); + } + } + if (hasHotbarShuffle) { + if (hasBuffer) { + lore.add(ColorUtil.translate("&7&m---»--*---------------------------*--«---")); + } + lore.add(ColorUtil.translate(this.getColor(hotbarShuffle) + "Hotbar Shuffle:")); + lore.add(ColorUtil.translate(" &8» &7Enabled: &c" + this.getColor(hotbarShuffle) + hotbarShuffle)); + lore.add(ColorUtil.translate(" &8» &7Minimum to Shuffle: &c" + this.getColor(hotbarShuffle) + minVlToShuffle)); + lore.add(ColorUtil.translate(" &8» &7Shuffle Every: &c" + this.getColor(hotbarShuffle) + shuffleEvery)); + lore.add(ColorUtil.translate("&7&m---»--*---------------------------*--«---")); + } + if (hasRandomRotation) { + lore.add(ColorUtil.translate(this.getColor(randomRotation) + "Random Rotation:")); + lore.add(ColorUtil.translate(" &8» &7Enabled: &c" + this.getColor(randomRotation) + randomRotation)); + lore.add(ColorUtil.translate(" &8» &7Minimum to Rotate: &c" + this.getColor(randomRotation) + minToRotate)); + lore.add(ColorUtil.translate(" &8» &7Rotate Every: &c" + this.getColor(randomRotation) + rotateEvery)); + lore.add(ColorUtil.translate("&7&m---»--*---------------------------*--«---")); + } + if (Config.ENABLED_CHECKS.get(checkClassName)) { + temporaryInventory.setItem(checkSlot, this.itemStack(XMaterial.GREEN_STAINED_GLASS_PANE.parseItem(), "&a" + parsedName, lore)); + } + else { + temporaryInventory.setItem(checkSlot, this.itemStack(XMaterial.RED_STAINED_GLASS_PANE.parseItem(), "&c" + parsedName, lore)); + } + } + ++offset; + } + ++currentPage; + this.inventoryList.add(temporaryInventory); + } + } + + public void open(final Player player, final int page) { + this.initializeInventory(); + this.currentPage.put(player.getUniqueId(), page); + player.openInventory(this.inventoryList.get(this.currentPage.get(player.getUniqueId()) - 1)); + } + + private String getColor(final boolean value) { + return value ? ChatColor.GREEN.toString() : ChatColor.RED.toString(); + } + + public List getCombatChecks() { + return this.combatChecks; + } + + public String getInventoryName() { + Objects.requireNonNull(this); + return "Manage Combat Checks"; + } + + public int getMaxPages() { + return this.maxPages; + } + + public HashMap getCurrentPage() { + return this.currentPage; + } + + public List getInventoryList() { + return this.inventoryList; + } + + public ItemStack getEnableAllItem() { + return this.enableAllItem; + } + + public ItemStack getDisableAllItem() { + return this.disableAllItem; + } + + public ItemStack getEnableAllPunishmentsItem() { + return this.enableAllPunishmentsItem; + } + + public ItemStack getDisableAllPunishmentsItem() { + return this.disableAllPunishmentsItem; + } + + public static CombatChecks getInstance() { + return CombatChecks.instance; + } + + static { + instance = new CombatChecks(); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/gui/impl/MainMenu.java b/src/main/java/me/frep/vulcan/spigot/gui/impl/MainMenu.java new file mode 100644 index 0000000..51de15a --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/gui/impl/MainMenu.java @@ -0,0 +1,75 @@ +package me.frep.vulcan.spigot.gui.impl; + +import org.bukkit.entity.Player; +import java.util.List; +import me.frep.vulcan.spigot.Vulcan; +import me.frep.vulcan.spigot.util.material.XMaterial; +import me.frep.vulcan.spigot.util.ColorUtil; +import java.util.ArrayList; +import me.frep.vulcan.spigot.config.Config; +import org.bukkit.inventory.Inventory; +import me.frep.vulcan.spigot.gui.VulcanGUI; + +public class MainMenu extends VulcanGUI +{ + public static final MainMenu instance; + private final String inventoryName; + private Inventory inventory; + + public MainMenu() { + this.inventoryName = Config.GUI_TITLE; + } + + private void initializeInventory() { + this.inventory = this.createInventory(27, this.inventoryName); + for (int i = 0; i < 27; ++i) { + this.inventory.setItem(i, this.glassPane()); + } + final List comingSoon = new ArrayList(); + comingSoon.add(""); + comingSoon.add(ColorUtil.translate("&cComing Soon..")); + final List disclaimer = new ArrayList(); + disclaimer.add(ColorUtil.translate("")); + disclaimer.add(ColorUtil.translate("&4&lWarning: &cEditing checks via the GUI can result")); + disclaimer.add(ColorUtil.translate("&cin config corruption. Editing from the config file")); + disclaimer.add(ColorUtil.translate("&cis recommended.")); + this.inventory.setItem(10, this.itemStack(XMaterial.CHEST.parseItem(), "&cManage Checks", disclaimer)); + final List topViolationsLore = new ArrayList(); + topViolationsLore.add(ColorUtil.translate("")); + topViolationsLore.add(ColorUtil.translate("&7Click to view top violations.")); + this.inventory.setItem(11, this.itemStack(XMaterial.DIAMOND.parseItem(), "&cTop Violations", topViolationsLore)); + final ArrayList bookString = new ArrayList(); + bookString.add(ColorUtil.translate("")); + bookString.add(ColorUtil.translate("&7Discord: &c5170#data")); + bookString.add(ColorUtil.translate("&7Support: &chttps://discord.isnow.dev/")); + bookString.add(ColorUtil.translate("")); + bookString.add(ColorUtil.translate("&7" + Vulcan.INSTANCE.getNonce())); + final String version = Vulcan.INSTANCE.getPlugin().getDescription().getVersion(); + this.inventory.setItem(13, this.itemStack(XMaterial.BOOK.parseItem(), "&cVulcan't v" + version + " by fap (data better) &7(" + Vulcan.INSTANCE.getSpigot() + "&7)", bookString)); + this.inventory.setItem(15, this.itemStack(XMaterial.OAK_SIGN.parseItem(), "&cSearch Player", comingSoon)); + this.inventory.setItem(16, this.itemStack(XMaterial.PAPER.parseItem(), "&cReload", this.noLore)); + } + + public void open(final Player player) { + if (this.inventory == null) { + this.initializeInventory(); + } + player.openInventory(this.inventory); + } + + public String getInventoryName() { + return this.inventoryName; + } + + public Inventory getInventory() { + return this.inventory; + } + + public static MainMenu getInstance() { + return MainMenu.instance; + } + + static { + instance = new MainMenu(); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/gui/impl/ManageCheck.java b/src/main/java/me/frep/vulcan/spigot/gui/impl/ManageCheck.java new file mode 100644 index 0000000..186f71c --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/gui/impl/ManageCheck.java @@ -0,0 +1,333 @@ +package me.frep.vulcan.spigot.gui.impl; + +import java.util.Objects; +import org.bukkit.entity.Player; +import java.util.Iterator; +import org.bukkit.ChatColor; +import me.frep.vulcan.spigot.util.material.XMaterial; +import me.frep.vulcan.spigot.util.ColorUtil; +import java.util.ArrayList; +import me.frep.vulcan.spigot.Vulcan; +import java.util.List; +import me.frep.vulcan.spigot.config.Config; +import org.apache.commons.lang.StringUtils; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Inventory; +import me.frep.vulcan.spigot.gui.VulcanGUI; + +public class ManageCheck extends VulcanGUI +{ + public static final ManageCheck instance; + private final String inventoryName = "Manage Check: "; + private Inventory inventory; + private ItemStack enabledItem; + private ItemStack punishableItem; + private ItemStack broadcastPunishmentItem; + private ItemStack punishmentCommandItem; + private ItemStack maxViolationsItem; + private ItemStack minimumViolationsToAlertItem; + private ItemStack alertIntervalItem; + private ItemStack goBackItem; + private ItemStack maxBufferItem; + private ItemStack bufferMultipleItem; + private ItemStack bufferDecayItem; + private ItemStack hotbarShuffleItem; + private ItemStack hotbarShuffleMinimumItem; + private ItemStack hotbarShuffleIntervalItem; + private ItemStack randomRotationItem; + private ItemStack randomRotationMinimumItem; + private ItemStack randomRotationIntervalItem; + private ItemStack maximumPingItem; + private ItemStack minimumTPSItem; + private String path; + private Class check; + + private void initializeInventory(final Class check) { + this.check = check; + final String checkClassName = check.getSimpleName(); + this.inventory = this.createInventory(54, "Manage Check: " + check.getSimpleName()); + String checkCategory = ""; + if (check.getName().contains("combat")) { + checkCategory = "combat"; + } + else if (check.getName().contains("movement")) { + checkCategory = "movement"; + } + else if (check.getName().contains("player")) { + checkCategory = "player"; + } + final CheckInfo checkInfo = (CheckInfo) check.getAnnotation(CheckInfo.class); + final String checkName = StringUtils.lowerCase(checkInfo.name()).replaceAll(" ", ""); + final char checkType = Character.toLowerCase(checkInfo.type()); + this.path = "checks." + checkCategory + "." + checkName + "." + checkType + "."; + final boolean enabled = Config.ENABLED_CHECKS.get(checkClassName); + final boolean punishable = Config.PUNISHABLE.get(checkClassName); + final boolean broadcastPunishment = Config.BROADCAST_PUNISHMENT.get(checkClassName); + final int maxViolations = Config.MAX_VIOLATIONS.get(checkClassName); + final int alertInterval = Config.ALERT_INTERVAL.get(checkClassName); + final int minimumViolationsToAlert = Config.MINIMUM_VL_TO_NOTIFY.get(checkClassName); + final int maximumPing = Config.MAXIMUM_PING.get(checkClassName); + final double minimumTPS = Config.MINIMUM_TPS.get(checkClassName); + final List punishmentCommands = Config.PUNISHMENT_COMMANDS.get(checkClassName); + final int maxBuffer = Config.MAX_BUFFERS.get(checkClassName); + final double bufferMultiple = Config.BUFFER_MULTIPLES.get(checkClassName); + final double bufferDecay = Config.BUFFER_DECAYS.get(checkClassName); + final boolean hotbarShuffle = Config.HOTBAR_SHUFFLE.get(checkClassName); + final int minVlToShuffle = Config.HOTBAR_SHUFFLE_MINIMUM.get(checkClassName); + final int shuffleEvery = Config.HOTBAR_SHUFFLE_EVERY.get(checkClassName); + final boolean randomRotation = Config.RANDOM_ROTATION.get(checkClassName); + final int minToRotate = Config.RANDOM_ROTATION_MINIMUM.get(checkClassName); + final int rotateEvery = Config.RANDOM_ROTATION_EVERY.get(checkClassName); + final boolean hasBuffer = Vulcan.INSTANCE.getPlugin().getConfig().isConfigurationSection(this.path + "buffer"); + final boolean hasHotbarShuffle = Vulcan.INSTANCE.getPlugin().getConfig().isConfigurationSection(this.path + "hotbar-shuffle"); + final boolean hasRandomRotation = Vulcan.INSTANCE.getPlugin().getConfig().isConfigurationSection(this.path + "random-rotation"); + final List maxViolationsLore = new ArrayList(); + maxViolationsLore.add(ColorUtil.translate("&7Current Max Violations: " + this.getColor(enabled) + maxViolations)); + maxViolationsLore.add(""); + maxViolationsLore.add(ColorUtil.translate("&7Click to Edit.")); + this.maxViolationsItem = this.itemStack(XMaterial.WRITABLE_BOOK.parseItem(), this.getColor(enabled) + "Set Max Violations", maxViolationsLore); + final List minimumViolationsToAlertLore = new ArrayList(); + minimumViolationsToAlertLore.add(ColorUtil.translate("&7Current Minimum Violations to Alert: " + this.getColor(enabled) + minimumViolationsToAlert)); + minimumViolationsToAlertLore.add(""); + minimumViolationsToAlertLore.add(ColorUtil.translate("&7Click to Edit.")); + this.minimumViolationsToAlertItem = this.itemStack(XMaterial.WRITABLE_BOOK.parseItem(), this.getColor(enabled) + "Set Minimum Violations to Alert", minimumViolationsToAlertLore); + final List enabledEnabledLore = new ArrayList(); + enabledEnabledLore.add(ColorUtil.translate("&7Click to &cdisable&7.")); + final List enabledDisabledLore = new ArrayList(); + enabledDisabledLore.add(ColorUtil.translate("&7Click to &aenable&7.")); + this.enabledItem = (enabled ? this.itemStack(XMaterial.GREEN_TERRACOTTA.parseItem(), "&aEnabled", enabledEnabledLore) : this.itemStack(XMaterial.RED_TERRACOTTA.parseItem(), "&cDisabled", enabledDisabledLore)); + final List punishableEnabledLore = new ArrayList(); + punishableEnabledLore.add(ColorUtil.translate("&7Click to &cdisable&7.")); + final List punishableDisabledLore = new ArrayList(); + punishableDisabledLore.add(ColorUtil.translate("&7Click to &aenable&7.")); + this.punishableItem = (punishable ? this.itemStack(XMaterial.GREEN_TERRACOTTA.parseItem(), "&aPunishable", punishableEnabledLore) : this.itemStack(XMaterial.RED_TERRACOTTA.parseItem(), "&cPunishable", punishableDisabledLore)); + final List broadcastPunishmentEnabledLore = new ArrayList(); + broadcastPunishmentEnabledLore.add(ColorUtil.translate("&7Click to &cdisable&7.")); + final List broadcastPunishmentDisabledLore = new ArrayList(); + broadcastPunishmentDisabledLore.add(ColorUtil.translate("&7Click to &aenable&7.")); + this.broadcastPunishmentItem = (broadcastPunishment ? this.itemStack(XMaterial.GREEN_TERRACOTTA.parseItem(), "&aBroadcast Punishment", broadcastPunishmentEnabledLore) : this.itemStack(XMaterial.RED_TERRACOTTA.parseItem(), "&cBroadcast Punishment", broadcastPunishmentDisabledLore)); + final List alertIntervalLore = new ArrayList(); + alertIntervalLore.add(ColorUtil.translate("&7Current Alert Interval: " + this.getColor(enabled) + alertInterval)); + alertIntervalLore.add(""); + alertIntervalLore.add(ColorUtil.translate("&7Click to Edit.")); + this.alertIntervalItem = this.itemStack(XMaterial.WRITABLE_BOOK.parseItem(), this.getColor(enabled) + "Set Alert Interval", alertIntervalLore); + final List punishmentCommandsLore = new ArrayList(); + punishmentCommandsLore.add(""); + punishmentCommandsLore.add(ColorUtil.translate(this.getColor(enabled) + "Punishment Commands:")); + for (String punishmentCommand : punishmentCommands) { + punishmentCommand = ColorUtil.translate(punishmentCommand); + if (punishmentCommand.length() > 40) { + punishmentCommandsLore.add(ColorUtil.translate(" &8» &7" + ChatColor.stripColor("Command too long to display."))); + } + else { + punishmentCommandsLore.add(ColorUtil.translate(" &8» &7" + ChatColor.stripColor(punishmentCommand))); + } + } + punishmentCommandsLore.add(""); + punishmentCommandsLore.add(ColorUtil.translate("&7Left Click to &aadd &7a command.")); + punishmentCommandsLore.add(ColorUtil.translate("&7Right Click to &cremove &7a command.")); + this.punishmentCommandItem = this.itemStack(XMaterial.WRITABLE_BOOK.parseItem(), this.getColor(enabled) + "Set Punishment Commands", punishmentCommandsLore); + final List maximumPingLore = new ArrayList(); + maximumPingLore.add(ColorUtil.translate("&7Current Maximum Ping: " + this.getColor(enabled) + maximumPing)); + maximumPingLore.add(""); + maximumPingLore.add(ColorUtil.translate("&7Click to Edit.")); + this.maximumPingItem = this.itemStack(XMaterial.WRITABLE_BOOK.parseItem(), this.getColor(enabled) + "Set Maximum Ping", maximumPingLore); + final List minimumTpsLore = new ArrayList(); + minimumTpsLore.add(ColorUtil.translate("&7Current Minimum TPS: " + this.getColor(enabled) + minimumTPS)); + minimumTpsLore.add(""); + minimumTpsLore.add(ColorUtil.translate("&7Click to Edit.")); + this.minimumTPSItem = this.itemStack(XMaterial.WRITABLE_BOOK.parseItem(), this.getColor(enabled) + "Set Minimum TPS", minimumTpsLore); + this.goBackItem = this.itemStack(XMaterial.REDSTONE_BLOCK.parseItem(), "&cGo Back", this.noLore); + if (hasBuffer) { + final List maxBufferLore = new ArrayList(); + maxBufferLore.add(ColorUtil.translate("&7Current Max Buffer: " + this.getColor(enabled) + maxBuffer)); + maxBufferLore.add(""); + maxBufferLore.add(ColorUtil.translate("&7Click to Edit.")); + this.maxBufferItem = this.itemStack(XMaterial.WRITABLE_BOOK.parseItem(), this.getColor(enabled) + "Set Max Buffer", maxBufferLore); + final List bufferMultipleLore = new ArrayList(); + bufferMultipleLore.add(ColorUtil.translate("&7Current Buffer Multiple: " + this.getColor(enabled) + bufferMultiple)); + bufferMultipleLore.add(""); + bufferMultipleLore.add(ColorUtil.translate("&7Click to Edit.")); + this.bufferMultipleItem = this.itemStack(XMaterial.WRITABLE_BOOK.parseItem(), this.getColor(enabled) + "Set Buffer Multiple", bufferMultipleLore); + final List bufferDecayLore = new ArrayList(); + bufferDecayLore.add(ColorUtil.translate("&7Current Buffer Decay: " + this.getColor(enabled) + bufferDecay)); + bufferDecayLore.add(""); + bufferDecayLore.add(ColorUtil.translate("&7Click to Edit.")); + this.bufferDecayItem = this.itemStack(XMaterial.WRITABLE_BOOK.parseItem(), this.getColor(enabled) + "Set Buffer Decay", bufferDecayLore); + } + if (hasHotbarShuffle) { + final List hotbarShuffleEnabledLore = new ArrayList(); + hotbarShuffleEnabledLore.add(ColorUtil.translate("&7Click to &cdisable&7.")); + final List hotbarShuffleDisabledLore = new ArrayList(); + hotbarShuffleDisabledLore.add(ColorUtil.translate("&7Click to &aenable&7.")); + this.hotbarShuffleItem = (hotbarShuffle ? this.itemStack(XMaterial.GREEN_TERRACOTTA.parseItem(), "&aHotbar Shuffle", hotbarShuffleEnabledLore) : this.itemStack(XMaterial.RED_TERRACOTTA.parseItem(), "&cHotbar Shuffle", hotbarShuffleDisabledLore)); + final List hotbarShuffleMinimumLore = new ArrayList(); + hotbarShuffleMinimumLore.add(ColorUtil.translate("&7Current Minimum Violations to Shuffle Hotbar: " + this.getColor(hotbarShuffle) + minVlToShuffle)); + hotbarShuffleMinimumLore.add(""); + hotbarShuffleMinimumLore.add(ColorUtil.translate("&7Click to Edit.")); + this.hotbarShuffleMinimumItem = this.itemStack(XMaterial.WRITABLE_BOOK.parseItem(), this.getColor(hotbarShuffle) + "Set Hotbar Shuffle Minimum Violations", hotbarShuffleMinimumLore); + final List hotbarShuffleIntervalLore = new ArrayList(); + hotbarShuffleIntervalLore.add(ColorUtil.translate("&7Current Hotbar Shuffle Interval: " + this.getColor(hotbarShuffle) + shuffleEvery)); + hotbarShuffleIntervalLore.add(""); + hotbarShuffleIntervalLore.add(ColorUtil.translate("&7Click to Edit.")); + this.hotbarShuffleIntervalItem = this.itemStack(XMaterial.WRITABLE_BOOK.parseItem(), this.getColor(hotbarShuffle) + "Set Hotbar Shuffle Interval", hotbarShuffleIntervalLore); + } + if (hasRandomRotation) { + final List randomRotationEnabledLore = new ArrayList(); + randomRotationEnabledLore.add(ColorUtil.translate("&7Click to &cdisable&7.")); + final List randomRotationDisabledLore = new ArrayList(); + randomRotationDisabledLore.add(ColorUtil.translate("&7Click to &aenable&7.")); + this.randomRotationItem = (randomRotation ? this.itemStack(XMaterial.GREEN_TERRACOTTA.parseItem(), "&aRandom Rotation", randomRotationEnabledLore) : this.itemStack(XMaterial.RED_TERRACOTTA.parseItem(), "&cRandom Rotation", randomRotationDisabledLore)); + final List randomRotationMinimumLore = new ArrayList(); + randomRotationMinimumLore.add(ColorUtil.translate("&7Current Minimum Violations to Rotate Randomly: " + this.getColor(randomRotation) + minToRotate)); + randomRotationMinimumLore.add(""); + randomRotationMinimumLore.add(ColorUtil.translate("&7Click to Edit.")); + this.randomRotationMinimumItem = this.itemStack(XMaterial.WRITABLE_BOOK.parseItem(), this.getColor(randomRotation) + "Set Random Rotation Minimum Violations", randomRotationMinimumLore); + final List randomRotationIntervalLore = new ArrayList(); + randomRotationIntervalLore.add(ColorUtil.translate("&7Current Random Rotation Interval: " + this.getColor(randomRotation) + rotateEvery)); + randomRotationIntervalLore.add(""); + randomRotationIntervalLore.add(ColorUtil.translate("&7Click to Edit.")); + this.randomRotationIntervalItem = this.itemStack(XMaterial.WRITABLE_BOOK.parseItem(), this.getColor(randomRotation) + "Set Random Rotation Interval", randomRotationIntervalLore); + } + for (int i = 0; i < 54; ++i) { + this.inventory.setItem(i, this.glassPane()); + } + this.inventory.setItem(9, this.maximumPingItem); + this.inventory.setItem(10, this.maxViolationsItem); + this.inventory.setItem(11, this.minimumViolationsToAlertItem); + this.inventory.setItem(12, this.enabledItem); + this.inventory.setItem(13, this.punishableItem); + this.inventory.setItem(14, this.broadcastPunishmentItem); + this.inventory.setItem(15, this.alertIntervalItem); + this.inventory.setItem(16, this.punishmentCommandItem); + this.inventory.setItem(17, this.minimumTPSItem); + this.inventory.setItem(28, this.goBackItem); + if (hasBuffer) { + this.inventory.setItem(30, this.maxBufferItem); + this.inventory.setItem(31, this.bufferMultipleItem); + this.inventory.setItem(32, this.bufferDecayItem); + } + this.inventory.setItem(34, this.goBackItem); + if (hasHotbarShuffle) { + this.inventory.setItem(46, this.hotbarShuffleItem); + this.inventory.setItem(47, this.hotbarShuffleMinimumItem); + this.inventory.setItem(48, this.hotbarShuffleIntervalItem); + } + if (hasRandomRotation) { + this.inventory.setItem(50, this.randomRotationIntervalItem); + this.inventory.setItem(51, this.randomRotationMinimumItem); + this.inventory.setItem(52, this.randomRotationItem); + } + } + + public void open(final Player player, final Class check) { + this.initializeInventory(check); + player.openInventory(this.inventory); + } + + private String getColor(final boolean value) { + return value ? ChatColor.GREEN.toString() : ChatColor.RED.toString(); + } + + public String getInventoryName() { + Objects.requireNonNull(this); + return "Manage Check: "; + } + + public Inventory getInventory() { + return this.inventory; + } + + public ItemStack getEnabledItem() { + return this.enabledItem; + } + + public ItemStack getPunishableItem() { + return this.punishableItem; + } + + public ItemStack getBroadcastPunishmentItem() { + return this.broadcastPunishmentItem; + } + + public ItemStack getPunishmentCommandItem() { + return this.punishmentCommandItem; + } + + public ItemStack getMaxViolationsItem() { + return this.maxViolationsItem; + } + + public ItemStack getMinimumViolationsToAlertItem() { + return this.minimumViolationsToAlertItem; + } + + public ItemStack getAlertIntervalItem() { + return this.alertIntervalItem; + } + + public ItemStack getGoBackItem() { + return this.goBackItem; + } + + public ItemStack getMaxBufferItem() { + return this.maxBufferItem; + } + + public ItemStack getBufferMultipleItem() { + return this.bufferMultipleItem; + } + + public ItemStack getBufferDecayItem() { + return this.bufferDecayItem; + } + + public ItemStack getHotbarShuffleItem() { + return this.hotbarShuffleItem; + } + + public ItemStack getHotbarShuffleMinimumItem() { + return this.hotbarShuffleMinimumItem; + } + + public ItemStack getHotbarShuffleIntervalItem() { + return this.hotbarShuffleIntervalItem; + } + + public ItemStack getRandomRotationItem() { + return this.randomRotationItem; + } + + public ItemStack getRandomRotationMinimumItem() { + return this.randomRotationMinimumItem; + } + + public ItemStack getRandomRotationIntervalItem() { + return this.randomRotationIntervalItem; + } + + public ItemStack getMaximumPingItem() { + return this.maximumPingItem; + } + + public ItemStack getMinimumTPSItem() { + return this.minimumTPSItem; + } + + public String getPath() { + return this.path; + } + + public Class getCheck() { + return this.check; + } + + public static ManageCheck getInstance() { + return ManageCheck.instance; + } + + static { + instance = new ManageCheck(); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/gui/impl/MovementChecks.java b/src/main/java/me/frep/vulcan/spigot/gui/impl/MovementChecks.java new file mode 100644 index 0000000..524c939 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/gui/impl/MovementChecks.java @@ -0,0 +1,212 @@ +package me.frep.vulcan.spigot.gui.impl; + +import java.util.Objects; +import org.bukkit.entity.Player; +import java.util.Iterator; +import org.bukkit.ChatColor; +import me.frep.vulcan.spigot.util.ColorUtil; +import me.frep.vulcan.spigot.Vulcan; +import me.frep.vulcan.spigot.config.Config; +import org.apache.commons.lang.StringUtils; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.util.material.XMaterial; +import java.util.Collection; +import java.util.Arrays; +import me.frep.vulcan.spigot.check.manager.CheckManager; +import java.util.ArrayList; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Inventory; +import java.util.UUID; +import java.util.HashMap; +import java.util.List; +import me.frep.vulcan.spigot.gui.VulcanGUI; + +public class MovementChecks extends VulcanGUI +{ + public static final MovementChecks instance; + private final List movementChecks; + private final String inventoryName = "Manage Movement Checks"; + private int maxPages; + private final HashMap currentPage; + private Inventory inventory; + private final List inventoryList; + private ItemStack enableAllItem; + private ItemStack disableAllItem; + private ItemStack enableAllPunishmentsItem; + private ItemStack disableAllPunishmentsItem; + + public MovementChecks() { + this.movementChecks = new ArrayList(); + this.currentPage = new HashMap(); + this.inventoryList = new ArrayList(); + } + + public void initializeInventory() { + this.inventoryList.clear(); + this.movementChecks.clear(); + this.inventory = this.createInventory(54, "Manage Movement Checks"); + final List classList = new ArrayList(Arrays.asList(CheckManager.CHECKS)); + for (final Class clazz : classList) { + if (clazz.getName().contains("movement")) { + this.movementChecks.add(clazz); + } + } + this.maxPages = 0; + this.maxPages = (int)Math.ceil(this.movementChecks.size() / 45.0); + int offset = 0; + int currentPage = 1; + for (int i = 0; i <= this.maxPages; ++i) { + final Inventory temporaryInventory = this.createInventory(54, "Manage Movement Checks [" + currentPage + "/" + this.maxPages + "]"); + for (int bottomRow = 46; bottomRow < 54; ++bottomRow) { + temporaryInventory.setItem(bottomRow, this.glassPane()); + } + this.enableAllItem = this.itemStack(XMaterial.GREEN_TERRACOTTA.parseItem(), "&aEnable All Checks", this.noLore); + this.disableAllItem = this.itemStack(XMaterial.RED_TERRACOTTA.parseItem(), "&cDisable All Checks", this.noLore); + this.disableAllPunishmentsItem = this.itemStack(XMaterial.RED_TERRACOTTA.parseItem(), "&cDisable All Punishments", this.noLore); + this.enableAllPunishmentsItem = this.itemStack(XMaterial.GREEN_TERRACOTTA.parseItem(), "&aEnable All Punishments", this.noLore); + temporaryInventory.setItem(45, this.arrow(false)); + temporaryInventory.setItem(46, this.enableAllItem); + temporaryInventory.setItem(47, this.disableAllItem); + temporaryInventory.setItem(51, this.disableAllPunishmentsItem); + temporaryInventory.setItem(52, this.enableAllPunishmentsItem); + temporaryInventory.setItem(53, this.arrow(true)); + temporaryInventory.setItem(49, this.itemStack(XMaterial.REDSTONE_BLOCK.parseItem(), "&cGo Back", this.noLore)); + for (int checkSlot = 0; checkSlot < 45; ++checkSlot) { + if (offset <= this.movementChecks.size() - 1) { + final String checkClassName = this.movementChecks.get(offset).getSimpleName(); + final CheckInfo checkInfo = (CheckInfo)this.movementChecks.get(offset).getAnnotation(CheckInfo.class); + final String checkName = checkInfo.name(); + final char checkType = checkInfo.type(); + final boolean experimental = checkInfo.experimental(); + final String description = checkInfo.description(); + String parsedName; + if (experimental) { + parsedName = checkName + " *(Type " + checkType + ")*"; + } + else { + parsedName = checkName + " (Type " + checkType + ")"; + } + final String checkNameToLowercase = StringUtils.lowerCase(checkInfo.name()).replaceAll(" ", ""); + final char checkTypeToLowercase = Character.toLowerCase(checkInfo.type()); + final String path = "checks.movement." + checkNameToLowercase + "." + checkTypeToLowercase + "."; + final boolean enabled = Config.ENABLED_CHECKS.get(checkClassName); + final boolean punishable = Config.PUNISHABLE.get(checkClassName); + final boolean broadcastPunishment = Config.BROADCAST_PUNISHMENT.get(checkClassName); + final int maxViolations = Config.MAX_VIOLATIONS.get(checkClassName); + final int maximumPing = Config.MAXIMUM_PING.get(checkClassName); + final double minimumTps = Config.MINIMUM_TPS.get(checkClassName); + final int alertEvery = Config.ALERT_INTERVAL.get(checkClassName); + final int alertMinimum = Config.MINIMUM_VL_TO_NOTIFY.get(checkClassName); + final List punishmentCommands = Config.PUNISHMENT_COMMANDS.get(checkClassName); + final int maxBuffer = Config.MAX_BUFFERS.get(checkClassName); + final double bufferMultiple = Config.BUFFER_MULTIPLES.get(checkClassName); + final double bufferDecay = Config.BUFFER_DECAYS.get(checkClassName); + final boolean hasBuffer = Vulcan.INSTANCE.getPlugin().getConfig().isConfigurationSection(path + "buffer"); + final List lore = new ArrayList(); + lore.add(ColorUtil.translate("&7&m---»--*---------------------------*--«---")); + lore.add(ColorUtil.translate("&7" + description)); + lore.add(ColorUtil.translate("&7&m---»--*---------------------------*--«---")); + lore.add(ColorUtil.translate(this.getColor(enabled) + "Settings:")); + lore.add(ColorUtil.translate(" &8» &7Enabled: " + this.getColor(enabled) + enabled)); + lore.add(ColorUtil.translate(" &8» &7Punishable: " + this.getColor(punishable) + punishable)); + lore.add(ColorUtil.translate(" &8» &7Broadcast Punishment: " + this.getColor(enabled) + broadcastPunishment)); + lore.add(ColorUtil.translate(" &8» &7Max Violations: &c" + this.getColor(enabled) + maxViolations)); + lore.add(ColorUtil.translate(" &8» &7Alert Interval: &c" + this.getColor(enabled) + alertEvery)); + lore.add(ColorUtil.translate(" &8» &7Minimum To Alert: &c" + this.getColor(enabled) + alertMinimum)); + lore.add(ColorUtil.translate(" &8» &7Maximum Ping: &c" + this.getColor(enabled) + maximumPing)); + lore.add(ColorUtil.translate(" &8» &7Minimum TPS: &c" + this.getColor(enabled) + minimumTps)); + lore.add(ColorUtil.translate("&7&m---»--*---------------------------*--«---")); + lore.add(ColorUtil.translate(this.getColor(enabled) + "Punishment Commands:")); + for (String punishmentCommand : punishmentCommands) { + punishmentCommand = ColorUtil.translate(punishmentCommand); + if (punishmentCommand.length() > 40) { + lore.add(ColorUtil.translate(" &8» &7" + ChatColor.stripColor("Command too long to display."))); + } + else { + lore.add(ColorUtil.translate(" &8» &7" + ChatColor.stripColor(punishmentCommand))); + } + } + if (!hasBuffer) { + lore.add(ColorUtil.translate("&7&m---»--*---------------------------*--«---")); + } + if (hasBuffer) { + lore.add(ColorUtil.translate("&7&m---»--*---------------------------*--«---")); + lore.add(ColorUtil.translate(this.getColor(enabled) + "Buffer:")); + lore.add(ColorUtil.translate(" &8» &7Max: &c" + this.getColor(enabled) + maxBuffer)); + lore.add(ColorUtil.translate(" &8» &7Multiple on Flag: &c" + this.getColor(enabled) + bufferMultiple)); + lore.add(ColorUtil.translate(" &8» &7Decay: &c" + this.getColor(enabled) + bufferDecay)); + lore.add(ColorUtil.translate("&7&m---»--*---------------------------*--«---")); + } + if (Config.ENABLED_CHECKS.get(checkClassName)) { + temporaryInventory.setItem(checkSlot, this.itemStack(XMaterial.GREEN_STAINED_GLASS_PANE.parseItem(), "&a" + parsedName, lore)); + } + else { + temporaryInventory.setItem(checkSlot, this.itemStack(XMaterial.RED_STAINED_GLASS_PANE.parseItem(), "&c" + parsedName, lore)); + } + } + ++offset; + } + ++currentPage; + this.inventoryList.add(temporaryInventory); + } + } + + public void open(final Player player, final int page) { + this.initializeInventory(); + this.currentPage.put(player.getUniqueId(), page); + player.openInventory(this.inventoryList.get(this.currentPage.get(player.getUniqueId()) - 1)); + } + + private String getColor(final boolean value) { + return value ? ChatColor.GREEN.toString() : ChatColor.RED.toString(); + } + + public List getMovementChecks() { + return this.movementChecks; + } + + public String getInventoryName() { + Objects.requireNonNull(this); + return "Manage Movement Checks"; + } + + public int getMaxPages() { + return this.maxPages; + } + + public HashMap getCurrentPage() { + return this.currentPage; + } + + public Inventory getInventory() { + return this.inventory; + } + + public List getInventoryList() { + return this.inventoryList; + } + + public ItemStack getEnableAllItem() { + return this.enableAllItem; + } + + public ItemStack getDisableAllItem() { + return this.disableAllItem; + } + + public ItemStack getEnableAllPunishmentsItem() { + return this.enableAllPunishmentsItem; + } + + public ItemStack getDisableAllPunishmentsItem() { + return this.disableAllPunishmentsItem; + } + + public static MovementChecks getInstance() { + return MovementChecks.instance; + } + + static { + instance = new MovementChecks(); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/gui/impl/PlayerChecks.java b/src/main/java/me/frep/vulcan/spigot/gui/impl/PlayerChecks.java new file mode 100644 index 0000000..dbb1780 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/gui/impl/PlayerChecks.java @@ -0,0 +1,212 @@ +package me.frep.vulcan.spigot.gui.impl; + +import java.util.Objects; +import org.bukkit.entity.Player; +import java.util.Iterator; +import org.bukkit.ChatColor; +import me.frep.vulcan.spigot.util.ColorUtil; +import me.frep.vulcan.spigot.Vulcan; +import me.frep.vulcan.spigot.config.Config; +import org.apache.commons.lang.StringUtils; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.util.material.XMaterial; +import java.util.Collection; +import java.util.Arrays; +import me.frep.vulcan.spigot.check.manager.CheckManager; +import java.util.ArrayList; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Inventory; +import java.util.UUID; +import java.util.HashMap; +import java.util.List; +import me.frep.vulcan.spigot.gui.VulcanGUI; + +public class PlayerChecks extends VulcanGUI +{ + public static final PlayerChecks instance; + private final List playerChecks; + private final String inventoryName = "Manage Player Checks"; + private int maxPages; + private final HashMap currentPage; + private Inventory inventory; + private final List inventoryList; + private ItemStack enableAllItem; + private ItemStack disableAllItem; + private ItemStack enableAllPunishmentsItem; + private ItemStack disableAllPunishmentsItem; + + public PlayerChecks() { + this.playerChecks = new ArrayList(); + this.currentPage = new HashMap(); + this.inventoryList = new ArrayList(); + } + + public void initializeInventory() { + this.inventoryList.clear(); + this.playerChecks.clear(); + this.inventory = this.createInventory(54, "Manage Player Checks"); + final List classList = new ArrayList(Arrays.asList(CheckManager.CHECKS)); + for (final Class clazz : classList) { + if (clazz.getName().contains("player")) { + this.playerChecks.add(clazz); + } + } + this.maxPages = 0; + this.maxPages = (int)Math.ceil(this.playerChecks.size() / 45.0); + int offset = 0; + int currentPage = 1; + for (int i = 0; i <= this.maxPages; ++i) { + final Inventory temporaryInventory = this.createInventory(54, "Manage Player Checks [" + currentPage + "/" + this.maxPages + "]"); + for (int bottomRow = 46; bottomRow < 54; ++bottomRow) { + temporaryInventory.setItem(bottomRow, this.glassPane()); + } + this.enableAllItem = this.itemStack(XMaterial.GREEN_TERRACOTTA.parseItem(), "&aEnable All Checks", this.noLore); + this.disableAllItem = this.itemStack(XMaterial.RED_TERRACOTTA.parseItem(), "&cDisable All Checks", this.noLore); + this.disableAllPunishmentsItem = this.itemStack(XMaterial.RED_TERRACOTTA.parseItem(), "&cDisable All Punishments", this.noLore); + this.enableAllPunishmentsItem = this.itemStack(XMaterial.GREEN_TERRACOTTA.parseItem(), "&aEnable All Punishments", this.noLore); + temporaryInventory.setItem(45, this.arrow(false)); + temporaryInventory.setItem(46, this.enableAllItem); + temporaryInventory.setItem(47, this.disableAllItem); + temporaryInventory.setItem(51, this.disableAllPunishmentsItem); + temporaryInventory.setItem(52, this.enableAllPunishmentsItem); + temporaryInventory.setItem(53, this.arrow(true)); + temporaryInventory.setItem(49, this.itemStack(XMaterial.REDSTONE_BLOCK.parseItem(), "&cGo Back", this.noLore)); + for (int checkSlot = 0; checkSlot < 45; ++checkSlot) { + if (offset <= this.playerChecks.size() - 1) { + final String checkClassName = this.playerChecks.get(offset).getSimpleName(); + final CheckInfo checkInfo = (CheckInfo)this.playerChecks.get(offset).getAnnotation(CheckInfo.class); + final String checkName = checkInfo.name(); + final char checkType = checkInfo.type(); + final boolean experimental = checkInfo.experimental(); + final String description = checkInfo.description(); + String parsedName; + if (experimental) { + parsedName = checkName + " *(Type " + checkType + ")*"; + } + else { + parsedName = checkName + " (Type " + checkType + ")"; + } + final String checkNameToLowercase = StringUtils.lowerCase(checkInfo.name()).replaceAll(" ", ""); + final char checkTypeToLowercase = Character.toLowerCase(checkInfo.type()); + final String path = "checks.player." + checkNameToLowercase + "." + checkTypeToLowercase + "."; + final boolean enabled = Config.ENABLED_CHECKS.get(checkClassName); + final boolean punishable = Config.PUNISHABLE.get(checkClassName); + final boolean broadcastPunishment = Config.BROADCAST_PUNISHMENT.get(checkClassName); + final int maxViolations = Config.MAX_VIOLATIONS.get(checkClassName); + final int maximumPing = Config.MAXIMUM_PING.get(checkClassName); + final double minimumTps = Config.MINIMUM_TPS.get(checkClassName); + final int alertEvery = Config.ALERT_INTERVAL.get(checkClassName); + final int alertMinimum = Config.MINIMUM_VL_TO_NOTIFY.get(checkClassName); + final List punishmentCommands = Config.PUNISHMENT_COMMANDS.get(checkClassName); + final int maxBuffer = Config.MAX_BUFFERS.get(checkClassName); + final double bufferMultiple = Config.BUFFER_MULTIPLES.get(checkClassName); + final double bufferDecay = Config.BUFFER_DECAYS.get(checkClassName); + final boolean hasBuffer = Vulcan.INSTANCE.getPlugin().getConfig().isConfigurationSection(path + "buffer"); + final List lore = new ArrayList(); + lore.add(ColorUtil.translate("&7&m---»--*---------------------------*--«---")); + lore.add(ColorUtil.translate("&7" + description)); + lore.add(ColorUtil.translate("&7&m---»--*---------------------------*--«---")); + lore.add(ColorUtil.translate(this.getColor(enabled) + "Settings:")); + lore.add(ColorUtil.translate(" &8» &7Enabled: " + this.getColor(enabled) + enabled)); + lore.add(ColorUtil.translate(" &8» &7Punishable: " + this.getColor(punishable) + punishable)); + lore.add(ColorUtil.translate(" &8» &7Broadcast Punishment: " + this.getColor(enabled) + broadcastPunishment)); + lore.add(ColorUtil.translate(" &8» &7Max Violations: &c" + this.getColor(enabled) + maxViolations)); + lore.add(ColorUtil.translate(" &8» &7Alert Interval: &c" + this.getColor(enabled) + alertEvery)); + lore.add(ColorUtil.translate(" &8» &7Minimum To Alert: &c" + this.getColor(enabled) + alertMinimum)); + lore.add(ColorUtil.translate(" &8» &7Maximum Ping: &c" + this.getColor(enabled) + maximumPing)); + lore.add(ColorUtil.translate(" &8» &7Minimum TPS: &c" + this.getColor(enabled) + minimumTps)); + lore.add(ColorUtil.translate("&7&m---»--*---------------------------*--«---")); + lore.add(ColorUtil.translate(this.getColor(enabled) + "Punishment Commands:")); + for (String punishmentCommand : punishmentCommands) { + punishmentCommand = ColorUtil.translate(punishmentCommand); + if (punishmentCommand.length() > 40) { + lore.add(ColorUtil.translate(" &8» &7" + ChatColor.stripColor("Command too long to display."))); + } + else { + lore.add(ColorUtil.translate(" &8» &7" + ChatColor.stripColor(punishmentCommand))); + } + } + if (!hasBuffer) { + lore.add(ColorUtil.translate("&7&m---»--*---------------------------*--«---")); + } + if (hasBuffer) { + lore.add(ColorUtil.translate("&7&m---»--*---------------------------*--«---")); + lore.add(ColorUtil.translate(this.getColor(enabled) + "Buffer:")); + lore.add(ColorUtil.translate(" &8» &7Max: &c" + this.getColor(enabled) + maxBuffer)); + lore.add(ColorUtil.translate(" &8» &7Multiple on Flag: &c" + this.getColor(enabled) + bufferMultiple)); + lore.add(ColorUtil.translate(" &8» &7Decay: &c" + this.getColor(enabled) + bufferDecay)); + lore.add(ColorUtil.translate("&7&m---»--*---------------------------*--«---")); + } + if (Config.ENABLED_CHECKS.get(checkClassName)) { + temporaryInventory.setItem(checkSlot, this.itemStack(XMaterial.GREEN_STAINED_GLASS_PANE.parseItem(), "&a" + parsedName, lore)); + } + else { + temporaryInventory.setItem(checkSlot, this.itemStack(XMaterial.RED_STAINED_GLASS_PANE.parseItem(), "&c" + parsedName, lore)); + } + } + ++offset; + } + ++currentPage; + this.inventoryList.add(temporaryInventory); + } + } + + public void open(final Player player, final int page) { + this.initializeInventory(); + this.currentPage.put(player.getUniqueId(), page); + player.openInventory(this.inventoryList.get(this.currentPage.get(player.getUniqueId()) - 1)); + } + + private String getColor(final boolean value) { + return value ? ChatColor.GREEN.toString() : ChatColor.RED.toString(); + } + + public List getPlayerChecks() { + return this.playerChecks; + } + + public String getInventoryName() { + Objects.requireNonNull(this); + return "Manage Player Checks"; + } + + public int getMaxPages() { + return this.maxPages; + } + + public HashMap getCurrentPage() { + return this.currentPage; + } + + public Inventory getInventory() { + return this.inventory; + } + + public List getInventoryList() { + return this.inventoryList; + } + + public ItemStack getEnableAllItem() { + return this.enableAllItem; + } + + public ItemStack getDisableAllItem() { + return this.disableAllItem; + } + + public ItemStack getEnableAllPunishmentsItem() { + return this.enableAllPunishmentsItem; + } + + public ItemStack getDisableAllPunishmentsItem() { + return this.disableAllPunishmentsItem; + } + + public static PlayerChecks getInstance() { + return PlayerChecks.instance; + } + + static { + instance = new PlayerChecks(); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/gui/manager/GUIManager.java b/src/main/java/me/frep/vulcan/spigot/gui/manager/GUIManager.java new file mode 100644 index 0000000..50ba548 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/gui/manager/GUIManager.java @@ -0,0 +1,891 @@ +package me.frep.vulcan.spigot.gui.manager; + +import net.wesjd.anvilgui.AnvilGUI; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.EventHandler; +import me.frep.vulcan.spigot.check.AbstractCheck; +import java.util.Iterator; +import org.bukkit.inventory.ItemStack; +import java.util.List; +import org.bukkit.plugin.Plugin; +import org.bukkit.Bukkit; +import org.apache.commons.lang.math.NumberUtils; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.gui.impl.ManageCheck; +import me.frep.vulcan.spigot.check.manager.CheckManager; +import org.apache.commons.lang.StringUtils; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import me.frep.vulcan.spigot.gui.impl.PlayerChecks; +import me.frep.vulcan.spigot.gui.impl.MovementChecks; +import me.frep.vulcan.spigot.gui.impl.CombatChecks; +import me.frep.vulcan.spigot.util.ColorUtil; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.Vulcan; +import me.frep.vulcan.spigot.gui.impl.CheckTypes; +import me.frep.vulcan.spigot.util.material.XMaterial; +import me.frep.vulcan.spigot.gui.impl.MainMenu; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import java.util.HashMap; +import java.util.UUID; +import java.util.Map; +import org.bukkit.event.Listener; +import me.frep.vulcan.spigot.gui.VulcanGUI; + +public class GUIManager extends VulcanGUI implements Listener +{ + private final Map addingPunishmentCommands; + private final Map removingPunishmentCommands; + private final Map configPath; + + public GUIManager() { + this.addingPunishmentCommands = new HashMap(); + this.removingPunishmentCommands = new HashMap(); + this.configPath = new HashMap(); + } + + @EventHandler + public void onClick(final InventoryClickEvent event) { + final Player player = (Player)event.getWhoClicked(); + if (event.getCurrentItem() == null) { + return; + } + final String title = event.getView().getTitle(); + final ItemStack item = event.getCurrentItem(); + final Material material = item.getType(); + if (title.equals(MainMenu.getInstance().getInventoryName())) { + event.setCancelled(true); + if (material.equals(XMaterial.CHEST.parseMaterial())) { + CheckTypes.getInstance().open(player); + } + if (material.equals(XMaterial.PAPER.parseMaterial())) { + Vulcan.INSTANCE.reload(); + player.sendMessage(ColorUtil.translate(Config.RELOAD_SUCCESS)); + } + if (material.equals(XMaterial.DIAMOND.parseMaterial())) { + player.performCommand("vulcan top"); + player.closeInventory(); + } + } + if (title.equals(CheckTypes.getInstance().getInventoryName())) { + event.setCancelled(true); + if (material.equals(XMaterial.REDSTONE_BLOCK.parseMaterial())) { + MainMenu.getInstance().open(player); + } + else if (material.equals(XMaterial.DIAMOND_SWORD.parseMaterial())) { + CombatChecks.getInstance().open(player, 1); + } + else if (material.equals(XMaterial.FEATHER.parseMaterial())) { + MovementChecks.getInstance().open(player, 1); + } + else if (material.equals(XMaterial.APPLE.parseMaterial())) { + PlayerChecks.getInstance().open(player, 1); + } + } + if (title.startsWith(CombatChecks.getInstance().getInventoryName())) { + event.setCancelled(true); + final int page = CombatChecks.getInstance().getCurrentPage().get(player.getUniqueId()); + if (material == Material.AIR) { + return; + } + final String className = ChatColor.stripColor(event.getCurrentItem().getItemMeta().getDisplayName().replaceAll(" ", "").replace("*", "").replaceAll("Type", "").replaceAll("\\(", "").replaceAll("\\)", "")); + if (material.equals(XMaterial.REDSTONE_BLOCK.parseMaterial())) { + CheckTypes.getInstance().open(player); + } + else if (item.equals(this.arrow(false))) { + if (page <= 1) { + player.sendMessage(ColorUtil.translate(Config.NO_PREVIOUS_PAGE)); + return; + } + CombatChecks.getInstance().open(player, page - 1); + } + else if (item.equals(this.arrow(true))) { + if (page == CombatChecks.getInstance().getMaxPages()) { + player.sendMessage(ColorUtil.translate(Config.NO_NEXT_PAGE)); + return; + } + CombatChecks.getInstance().open(player, page + 1); + CombatChecks.getInstance().open(player, page + 1); + } + else if (item.equals(CombatChecks.getInstance().getEnableAllItem())) { + final List combatChecks = CombatChecks.getInstance().getCombatChecks(); + for (final Class clazz : combatChecks) { + final String checkClassName = clazz.getSimpleName(); + final CheckInfo checkInfo = (CheckInfo) clazz.getAnnotation(CheckInfo.class); + String checkName = StringUtils.lowerCase(checkInfo.name()).replaceAll(" ", ""); + final char checkType = Character.toLowerCase(checkInfo.type()); + String path = "checks.combat." + checkName + "." + checkType + "."; + Config.ENABLED_CHECKS.remove(checkClassName); + Config.ENABLED_CHECKS.put(checkClassName, true); + Config.setValue(path + "enabled", true); + } + CombatChecks.getInstance().open(player, page); + player.sendMessage(ColorUtil.translate(Config.ENABLED_ALL_CHECKS)); + } + else if (item.equals(CombatChecks.getInstance().getDisableAllItem())) { + final List combatChecks = CombatChecks.getInstance().getCombatChecks(); + for (final Class clazz : combatChecks) { + final String checkClassName = clazz.getSimpleName(); + final CheckInfo checkInfo = (CheckInfo) clazz.getAnnotation(CheckInfo.class); + String checkName = StringUtils.lowerCase(checkInfo.name()).replaceAll(" ", ""); + final char checkType = Character.toLowerCase(checkInfo.type()); + String path = "checks.combat." + checkName + "." + checkType + "."; + Config.ENABLED_CHECKS.remove(checkClassName); + Config.ENABLED_CHECKS.put(checkClassName, false); + Config.setValue(path + "enabled", false); + } + CombatChecks.getInstance().open(player, page); + player.sendMessage(ColorUtil.translate(Config.DISABLED_ALL_CHECKS)); + } + else if (item.equals(CombatChecks.getInstance().getEnableAllPunishmentsItem())) { + final List combatChecks = CombatChecks.getInstance().getCombatChecks(); + for (final Class clazz : combatChecks) { + final String checkClassName = clazz.getSimpleName(); + final CheckInfo checkInfo = (CheckInfo) clazz.getAnnotation(CheckInfo.class); + String checkName = StringUtils.lowerCase(checkInfo.name()).replaceAll(" ", ""); + final char checkType = Character.toLowerCase(checkInfo.type()); + String path = "checks.combat." + checkName + "." + checkType + "."; + Config.PUNISHABLE.remove(checkClassName); + Config.PUNISHABLE.put(checkClassName, true); + Config.setValue(path + "punishable", true); + } + CombatChecks.getInstance().open(player, page); + player.sendMessage(ColorUtil.translate(Config.ENABLED_ALL_PUNISHMENTS)); + } + else if (item.equals(CombatChecks.getInstance().getDisableAllPunishmentsItem())) { + final List combatChecks = CombatChecks.getInstance().getCombatChecks(); + for (final Class clazz : combatChecks) { + final String checkClassName = clazz.getSimpleName(); + final CheckInfo checkInfo = (CheckInfo) clazz.getAnnotation(CheckInfo.class); + String checkName = StringUtils.lowerCase(checkInfo.name()).replaceAll(" ", ""); + final char checkType = Character.toLowerCase(checkInfo.type()); + String path = "checks.combat." + checkName + "." + checkType + "."; + Config.PUNISHABLE.remove(checkClassName); + Config.PUNISHABLE.put(checkClassName, false); + Config.setValue(path + "punishable", false); + } + CombatChecks.getInstance().open(player, page); + player.sendMessage(ColorUtil.translate(Config.DISABLED_ALL_PUNISHMENTS)); + } + else { + for(Class check : CheckManager.CHECKS) { + if (check.getSimpleName().equals(className)) { + ManageCheck.getInstance().open(player, check); + } + } + } + } + if (title.startsWith(MovementChecks.getInstance().getInventoryName())) { + event.setCancelled(true); + final int page = MovementChecks.getInstance().getCurrentPage().get(player.getUniqueId()); + if (material == Material.AIR) { + return; + } + final String className = ChatColor.stripColor(event.getCurrentItem().getItemMeta().getDisplayName().replaceAll(" ", "").replace("*", "").replaceAll("Type", "").replaceAll("\\(", "").replaceAll("\\)", "")); + if (material.equals(XMaterial.REDSTONE_BLOCK.parseMaterial())) { + CheckTypes.getInstance().open(player); + } + else if (item.equals(this.arrow(false))) { + if (page <= 1) { + player.sendMessage(ColorUtil.translate(Config.NO_PREVIOUS_PAGE)); + return; + } + MovementChecks.getInstance().open(player, page - 1); + } + else if (item.equals(this.arrow(true))) { + if (page == MovementChecks.getInstance().getMaxPages()) { + player.sendMessage(ColorUtil.translate(Config.NO_NEXT_PAGE)); + return; + } + MovementChecks.getInstance().open(player, page + 1); + MovementChecks.getInstance().open(player, page + 1); + } + else if (item.equals(MovementChecks.getInstance().getEnableAllItem())) { + final List movementChecks = MovementChecks.getInstance().getMovementChecks(); + for (final Class clazz : movementChecks) { + final String checkClassName = clazz.getSimpleName(); + final CheckInfo checkInfo = (CheckInfo) clazz.getAnnotation(CheckInfo.class); + final String checkName = StringUtils.lowerCase(checkInfo.name()).replaceAll(" ", ""); + final char checkType = Character.toLowerCase(checkInfo.type()); + final String path = "checks.movement." + checkName + "." + checkType + "."; + Config.ENABLED_CHECKS.remove(checkClassName); + Config.ENABLED_CHECKS.put(checkClassName, true); + Config.setValue(path + "enabled", true); + } + MovementChecks.getInstance().open(player, page); + player.sendMessage(ColorUtil.translate(Config.ENABLED_ALL_CHECKS)); + } + else if (item.equals(MovementChecks.getInstance().getDisableAllItem())) { + final List movementChecks = MovementChecks.getInstance().getMovementChecks(); + for (final Class clazz : movementChecks) { + final String checkClassName = clazz.getSimpleName(); + final CheckInfo checkInfo = (CheckInfo) clazz.getAnnotation(CheckInfo.class); + final String checkName = StringUtils.lowerCase(checkInfo.name()).replaceAll(" ", ""); + final char checkType = Character.toLowerCase(checkInfo.type()); + final String path = "checks.movement." + checkName + "." + checkType + "."; + Config.ENABLED_CHECKS.remove(checkClassName); + Config.ENABLED_CHECKS.put(checkClassName, false); + Config.setValue(path + "enabled", false); + } + MovementChecks.getInstance().open(player, page); + player.sendMessage(ColorUtil.translate(Config.DISABLED_ALL_CHECKS)); + } + else if (item.equals(MovementChecks.getInstance().getEnableAllPunishmentsItem())) { + final List movementChecks = MovementChecks.getInstance().getMovementChecks(); + for (final Class clazz : movementChecks) { + final String checkClassName = clazz.getSimpleName(); + final CheckInfo checkInfo = (CheckInfo) clazz.getAnnotation(CheckInfo.class); + final String checkName = StringUtils.lowerCase(checkInfo.name()).replaceAll(" ", ""); + final char checkType = Character.toLowerCase(checkInfo.type()); + final String path = "checks.movement." + checkName + "." + checkType + "."; + Config.PUNISHABLE.remove(checkClassName); + Config.PUNISHABLE.put(checkClassName, true); + Config.setValue(path + "punishable", true); + } + MovementChecks.getInstance().open(player, page); + player.sendMessage(ColorUtil.translate(Config.ENABLED_ALL_PUNISHMENTS)); + } + else if (item.equals(MovementChecks.getInstance().getDisableAllPunishmentsItem())) { + final List movementChecks = MovementChecks.getInstance().getMovementChecks(); + for (final Class clazz : movementChecks) { + final String checkClassName = clazz.getSimpleName(); + final CheckInfo checkInfo = (CheckInfo) clazz.getAnnotation(CheckInfo.class); + final String checkName = StringUtils.lowerCase(checkInfo.name()).replaceAll(" ", ""); + final char checkType = Character.toLowerCase(checkInfo.type()); + final String path = "checks.movement." + checkName + "." + checkType + "."; + Config.PUNISHABLE.remove(checkClassName); + Config.PUNISHABLE.put(checkClassName, false); + Config.setValue(path + "punishable", false); + } + MovementChecks.getInstance().open(player, page); + player.sendMessage(ColorUtil.translate(Config.DISABLED_ALL_PUNISHMENTS)); + } + else { + for(Class check : CheckManager.CHECKS) { + if (check.getSimpleName().equals(className)) { + ManageCheck.getInstance().open(player, check); + } + } + } + } + if (title.startsWith(PlayerChecks.getInstance().getInventoryName())) { + event.setCancelled(true); + final int page = PlayerChecks.getInstance().getCurrentPage().get(player.getUniqueId()); + if (material == Material.AIR) { + return; + } + final String className = ChatColor.stripColor(event.getCurrentItem().getItemMeta().getDisplayName().replaceAll(" ", "").replace("*", "").replaceAll("Type", "").replaceAll("\\(", "").replaceAll("\\)", "")); + if (material.equals(XMaterial.REDSTONE_BLOCK.parseMaterial())) { + CheckTypes.getInstance().open(player); + } + else if (item.equals(this.arrow(false))) { + if (page <= 1) { + player.sendMessage(ColorUtil.translate(Config.NO_PREVIOUS_PAGE)); + return; + } + PlayerChecks.getInstance().open(player, page - 1); + } + else if (item.equals(this.arrow(true))) { + if (page == PlayerChecks.getInstance().getMaxPages()) { + player.sendMessage(ColorUtil.translate(Config.NO_NEXT_PAGE)); + return; + } + PlayerChecks.getInstance().open(player, page + 1); + PlayerChecks.getInstance().open(player, page + 1); + } + else if (item.equals(PlayerChecks.getInstance().getEnableAllItem())) { + final List playerChecks = PlayerChecks.getInstance().getPlayerChecks(); + for (final Class clazz : playerChecks) { + final String checkClassName = clazz.getSimpleName(); + final CheckInfo checkInfo = (CheckInfo) clazz.getAnnotation(CheckInfo.class); + final String checkName = StringUtils.lowerCase(checkInfo.name()).replaceAll(" ", ""); + final char checkType = Character.toLowerCase(checkInfo.type()); + final String path = "checks.player." + checkName + "." + checkType + "."; + Config.ENABLED_CHECKS.remove(checkClassName); + Config.ENABLED_CHECKS.put(checkClassName, true); + Config.setValue(path + "enabled", true); + } + PlayerChecks.getInstance().open(player, page); + player.sendMessage(ColorUtil.translate(Config.ENABLED_ALL_CHECKS)); + } + else if (item.equals(PlayerChecks.getInstance().getDisableAllItem())) { + final List playerChecks = PlayerChecks.getInstance().getPlayerChecks(); + for (final Class clazz : playerChecks) { + final String checkClassName = clazz.getSimpleName(); + final CheckInfo checkInfo = (CheckInfo) clazz.getAnnotation(CheckInfo.class); + final String checkName = StringUtils.lowerCase(checkInfo.name()).replaceAll(" ", ""); + final char checkType = Character.toLowerCase(checkInfo.type()); + final String path = "checks.player." + checkName + "." + checkType + "."; + Config.ENABLED_CHECKS.remove(checkClassName); + Config.ENABLED_CHECKS.put(checkClassName, false); + Config.setValue(path + "enabled", false); + } + PlayerChecks.getInstance().open(player, page); + player.sendMessage(ColorUtil.translate(Config.DISABLED_ALL_CHECKS)); + } + else if (item.equals(PlayerChecks.getInstance().getEnableAllPunishmentsItem())) { + final List playerChecks = PlayerChecks.getInstance().getPlayerChecks(); + for (final Class clazz : playerChecks) { + final String checkClassName = clazz.getSimpleName(); + final CheckInfo checkInfo = (CheckInfo) clazz.getAnnotation(CheckInfo.class); + final String checkName = StringUtils.lowerCase(checkInfo.name()).replaceAll(" ", ""); + final char checkType = Character.toLowerCase(checkInfo.type()); + final String path = "checks.player." + checkName + "." + checkType + "."; + Config.PUNISHABLE.remove(checkClassName); + Config.PUNISHABLE.put(checkClassName, true); + Config.setValue(path + "punishable", true); + } + PlayerChecks.getInstance().open(player, page); + player.sendMessage(ColorUtil.translate(Config.ENABLED_ALL_PUNISHMENTS)); + } + else if (item.equals(PlayerChecks.getInstance().getDisableAllPunishmentsItem())) { + final List playerChecks = PlayerChecks.getInstance().getPlayerChecks(); + for (final Class clazz : playerChecks) { + final String checkClassName = clazz.getSimpleName(); + final CheckInfo checkInfo = (CheckInfo) clazz.getAnnotation(CheckInfo.class); + final String checkName = StringUtils.lowerCase(checkInfo.name()).replaceAll(" ", ""); + final char checkType = Character.toLowerCase(checkInfo.type()); + final String path = "checks.player." + checkName + "." + checkType + "."; + Config.PUNISHABLE.remove(checkClassName); + Config.PUNISHABLE.put(checkClassName, false); + Config.setValue(path + "punishable", false); + } + PlayerChecks.getInstance().open(player, page); + player.sendMessage(ColorUtil.translate(Config.DISABLED_ALL_PUNISHMENTS)); + } + else { + for(Class check : CheckManager.CHECKS) { + if (check.getSimpleName().equals(className)) { + ManageCheck.getInstance().open(player, check); + } + } + } + } + if (title.startsWith(ManageCheck.getInstance().getInventoryName())) { + event.setCancelled(true); + final String checkName = title.split(": ")[1]; + final String path = ManageCheck.getInstance().getPath(); + final Class check = ManageCheck.getInstance().getCheck(); + String checkCategory = ""; + if (check.getName().contains("combat")) { + checkCategory = "combat"; + } + else if (check.getName().contains("movement")) { + checkCategory = "movement"; + } + else if (check.getName().contains("player")) { + checkCategory = "player"; + } + if (item.equals(ManageCheck.getInstance().getEnabledItem())) { + if (Config.ENABLED_CHECKS.get(checkName)) { + Config.ENABLED_CHECKS.remove(checkName); + Config.ENABLED_CHECKS.put(checkName, false); + Config.setValue(path + "enabled", false); + player.sendMessage(ColorUtil.translate(Config.DISABLED_CHECK.replaceAll("%check%", checkName))); + } + else { + Config.ENABLED_CHECKS.remove(checkName); + Config.ENABLED_CHECKS.put(checkName, true); + Config.setValue(path + "enabled", true); + player.sendMessage(ColorUtil.translate(Config.ENABLED_CHECK.replaceAll("%check%", checkName))); + } + ManageCheck.getInstance().open(player, ManageCheck.getInstance().getCheck()); + } + else if (item.equals(ManageCheck.getInstance().getPunishableItem())) { + if (Config.PUNISHABLE.get(checkName)) { + Config.PUNISHABLE.remove(checkName); + Config.PUNISHABLE.put(checkName, false); + Config.setValue(path + "punishable", false); + player.sendMessage(ColorUtil.translate(Config.DISABLED_PUNISHMENT.replaceAll("%check%", checkName))); + } + else { + Config.PUNISHABLE.remove(checkName); + Config.PUNISHABLE.put(checkName, true); + Config.setValue(path + "punishable", true); + player.sendMessage(ColorUtil.translate(Config.ENABLED_PUNISHMENT.replaceAll("%check%", checkName))); + } + ManageCheck.getInstance().open(player, ManageCheck.getInstance().getCheck()); + } + else if (item.equals(ManageCheck.getInstance().getHotbarShuffleItem())) { + if (Config.HOTBAR_SHUFFLE.get(checkName)) { + Config.HOTBAR_SHUFFLE.remove(checkName); + Config.HOTBAR_SHUFFLE.put(checkName, false); + Config.setValue(path + "hotbar-shuffle.enabled", false); + player.sendMessage(ColorUtil.translate(Config.DISABLED_HOTBAR_SHUFFLE.replaceAll("%check%", checkName))); + } + else { + Config.HOTBAR_SHUFFLE.remove(checkName); + Config.HOTBAR_SHUFFLE.put(checkName, true); + Config.setValue(path + "hotbar-shuffle.enabled", true); + player.sendMessage(ColorUtil.translate(Config.ENABLED_HOTBAR_SHUFFLE.replaceAll("%check%", checkName))); + } + ManageCheck.getInstance().open(player, ManageCheck.getInstance().getCheck()); + } + else if (item.equals(ManageCheck.getInstance().getRandomRotationItem())) { + if (Config.RANDOM_ROTATION.get(checkName)) { + Config.RANDOM_ROTATION.remove(checkName); + Config.RANDOM_ROTATION.put(checkName, false); + Config.setValue(path + "random-rotation.enabled", false); + player.sendMessage(ColorUtil.translate(Config.DISABLED_RANDOM_ROTATION.replaceAll("%check%", checkName))); + } + else { + Config.RANDOM_ROTATION.remove(checkName); + Config.RANDOM_ROTATION.put(checkName, true); + Config.setValue(path + "random-rotation.enabled", true); + player.sendMessage(ColorUtil.translate(Config.ENABLED_RANDOM_ROTATION.replaceAll("%check%", checkName))); + } + ManageCheck.getInstance().open(player, ManageCheck.getInstance().getCheck()); + } + else if (item.equals(ManageCheck.getInstance().getBroadcastPunishmentItem())) { + if (Config.BROADCAST_PUNISHMENT.get(checkName)) { + Config.BROADCAST_PUNISHMENT.remove(checkName); + Config.BROADCAST_PUNISHMENT.put(checkName, false); + Config.setValue(path + "broadcast-punishment", false); + player.sendMessage(ColorUtil.translate(Config.DISABLED_BROADCAST_PUNISHMENT.replaceAll("%check%", checkName))); + } + else { + Config.BROADCAST_PUNISHMENT.remove(checkName); + Config.BROADCAST_PUNISHMENT.put(checkName, true); + player.sendMessage(ColorUtil.translate(Config.ENABLED_BROADCAST_PUNISHMENT.replaceAll("%check%", checkName))); + } + ManageCheck.getInstance().open(player, ManageCheck.getInstance().getCheck()); + } + else if (item.equals(ManageCheck.getInstance().getMaxBufferItem())) { + if (ServerUtil.isHigherThan1_17()) { + player.sendMessage(ColorUtil.translate("&cThis is unavailable on 1.17 servers!")); + return; + } + final int defaultMaxBuffer = Config.MAX_BUFFERS.get(checkName); + new AnvilGUI.Builder().onComplete((player1, s) -> { + if (!NumberUtils.isNumber(s) || s.contains(".")) { + return AnvilGUI.Response.text(ColorUtil.translate(Config.MUST_BE_AN_INTEGER)); + } + else { + final int maxBuffer = Integer.parseInt(s); + if (maxBuffer < 0) { + return AnvilGUI.Response.text(ColorUtil.translate(Config.MUST_BE_POSITIVE)); + } + else { + Config.MAX_BUFFERS.remove(checkName); + Config.MAX_BUFFERS.put(checkName, maxBuffer); + Config.setValue(path + "buffer.max", maxBuffer); + player.sendMessage(ColorUtil.translate(Config.SET_MAX_BUFFER.replaceAll("%check%", checkName).replaceAll("%value%", Integer.toString(maxBuffer)))); + Bukkit.getScheduler().scheduleSyncDelayedTask(Vulcan.INSTANCE.getPlugin(), () -> ManageCheck.getInstance().open(player, check), 2L); + return AnvilGUI.Response.close(); + } + } + }).text("Current Value: " + defaultMaxBuffer).item(XMaterial.PAPER.parseItem()).plugin(Vulcan.INSTANCE.getPlugin()).open(player); + } + else if (item.equals(ManageCheck.getInstance().getHotbarShuffleMinimumItem())) { + if (ServerUtil.isHigherThan1_17()) { + player.sendMessage(ColorUtil.translate("&cThis is unavailable on 1.17 servers!")); + return; + } + final int defaultMinToHotbarShuffleViolations = Config.HOTBAR_SHUFFLE_MINIMUM.get(checkName); + new AnvilGUI.Builder().onComplete((player1, s) -> { + if (!NumberUtils.isNumber(s) || s.contains(".")) { + return AnvilGUI.Response.text(ColorUtil.translate(Config.MUST_BE_AN_INTEGER)); + } + else { + final int minVlToShuffleHotbar = Integer.parseInt(s); + if (minVlToShuffleHotbar < 0) { + return AnvilGUI.Response.text(ColorUtil.translate(Config.MUST_BE_POSITIVE)); + } + else { + Config.HOTBAR_SHUFFLE_MINIMUM.remove(checkName); + Config.HOTBAR_SHUFFLE_MINIMUM.put(checkName, minVlToShuffleHotbar); + Config.setValue(path + "hotbar-shuffle.minimum-vl-to-shuffle", minVlToShuffleHotbar); + player.sendMessage(ColorUtil.translate(Config.SET_HOTBAR_SHUFFLE_MINIMUM_VIOLATIONS.replaceAll("%check%", checkName).replaceAll("%value%", Integer.toString(minVlToShuffleHotbar)))); + Bukkit.getScheduler().scheduleSyncDelayedTask(Vulcan.INSTANCE.getPlugin(), () -> ManageCheck.getInstance().open(player, check), 2L); + return AnvilGUI.Response.close(); + } + } + }).text("Current Value: " + defaultMinToHotbarShuffleViolations).item(XMaterial.PAPER.parseItem()).plugin(Vulcan.INSTANCE.getPlugin()).open(player); + } + else if (item.equals(ManageCheck.getInstance().getHotbarShuffleIntervalItem())) { + if (ServerUtil.isHigherThan1_17()) { + player.sendMessage(ColorUtil.translate("&cThis is unavailable on 1.17 servers!")); + return; + } + final int defaultHotbarShuffleInterval = Config.HOTBAR_SHUFFLE_EVERY.get(checkName); + new AnvilGUI.Builder().onComplete((player1, s) -> { + if (!NumberUtils.isNumber(s) || s.contains(".")) { + return AnvilGUI.Response.text(ColorUtil.translate(Config.MUST_BE_AN_INTEGER)); + } + else { + final int hotbarShuffleInterval = Integer.parseInt(s); + if (hotbarShuffleInterval < 0) { + return AnvilGUI.Response.text(ColorUtil.translate(Config.MUST_BE_POSITIVE)); + } + else { + Config.HOTBAR_SHUFFLE_EVERY.remove(checkName); + Config.HOTBAR_SHUFFLE_EVERY.put(checkName, hotbarShuffleInterval); + Config.setValue(path + "hotbar-shuffle.shuffle-every", hotbarShuffleInterval); + player.sendMessage(ColorUtil.translate(Config.SET_HOTBAR_SHUFFLE_INTERVAL.replaceAll("%check%", checkName).replaceAll("%value%", Integer.toString(hotbarShuffleInterval)))); + Bukkit.getScheduler().scheduleSyncDelayedTask(Vulcan.INSTANCE.getPlugin(), () -> ManageCheck.getInstance().open(player, check), 2L); + return AnvilGUI.Response.close(); + } + } + }).text("Current Value: " + defaultHotbarShuffleInterval).item(XMaterial.PAPER.parseItem()).plugin(Vulcan.INSTANCE.getPlugin()).open(player); + } + else if (item.equals(ManageCheck.getInstance().getRandomRotationMinimumItem())) { + if (ServerUtil.isHigherThan1_17()) { + player.sendMessage(ColorUtil.translate("&cThis is unavailable on 1.17 servers!")); + return; + } + final int defaultRandomRotationMinimum = Config.RANDOM_ROTATION_MINIMUM.get(checkName); + new AnvilGUI.Builder().onComplete((player1, s) -> { + if (!NumberUtils.isNumber(s) || s.contains(".")) { + return AnvilGUI.Response.text(ColorUtil.translate(Config.MUST_BE_AN_INTEGER)); + } + else { + final int randomRotationMinimum = Integer.parseInt(s); + if (randomRotationMinimum < 0) { + return AnvilGUI.Response.text(ColorUtil.translate(Config.MUST_BE_POSITIVE)); + } + else { + Config.RANDOM_ROTATION_MINIMUM.remove(checkName); + Config.RANDOM_ROTATION_MINIMUM.put(checkName, randomRotationMinimum); + Config.setValue(path + "random-rotation.minimum-vl-to-randomly-rotate", randomRotationMinimum); + player.sendMessage(ColorUtil.translate(Config.SET_RANDOM_ROTATION_MINIMUM_VIOLATIONS.replaceAll("%check%", checkName).replaceAll("%value%", Integer.toString(randomRotationMinimum)))); + Bukkit.getScheduler().scheduleSyncDelayedTask(Vulcan.INSTANCE.getPlugin(), () -> ManageCheck.getInstance().open(player, check), 2L); + return AnvilGUI.Response.close(); + } + } + }).text("Current Value: " + defaultRandomRotationMinimum).item(XMaterial.PAPER.parseItem()).plugin(Vulcan.INSTANCE.getPlugin()).open(player); + } + else if (item.equals(ManageCheck.getInstance().getMaximumPingItem())) { + if (ServerUtil.isHigherThan1_17()) { + player.sendMessage(ColorUtil.translate("&cThis is unavailable on 1.17 servers!")); + return; + } + final int defaultMaxPing = Config.MAXIMUM_PING.get(checkName); + new AnvilGUI.Builder().onComplete((player1, s) -> { + if (!NumberUtils.isNumber(s) || s.contains(".")) { + return AnvilGUI.Response.text(ColorUtil.translate(Config.MUST_BE_AN_INTEGER)); + } + else { + final int maximumPing = Integer.parseInt(s); + if (maximumPing < 0) { + return AnvilGUI.Response.text(ColorUtil.translate(Config.MUST_BE_POSITIVE)); + } + else { + Config.MAXIMUM_PING.remove(checkName); + Config.MAXIMUM_PING.put(checkName, maximumPing); + Config.setValue(path + "maximum-ping", maximumPing); + player.sendMessage(ColorUtil.translate(Config.SET_MAXIMUM_PING.replaceAll("%check%", checkName).replaceAll("%value%", Integer.toString(maximumPing)))); + Bukkit.getScheduler().scheduleSyncDelayedTask(Vulcan.INSTANCE.getPlugin(), () -> ManageCheck.getInstance().open(player, check), 2L); + return AnvilGUI.Response.close(); + } + } + }).text("Current Value: " + defaultMaxPing).item(XMaterial.PAPER.parseItem()).plugin(Vulcan.INSTANCE.getPlugin()).open(player); + } + else if (item.equals(ManageCheck.getInstance().getMinimumTPSItem())) { + if (ServerUtil.isHigherThan1_17()) { + player.sendMessage(ColorUtil.translate("&cThis is unavailable on 1.17 servers!")); + return; + } + final double defaultMinimumTPS = Config.MINIMUM_TPS.get(checkName); + new AnvilGUI.Builder().onComplete((player1, s) -> { + if (!NumberUtils.isNumber(s)) { + return AnvilGUI.Response.text(ColorUtil.translate(Config.MUST_BE_NUMBER)); + } + else { + final double minimumTPS = Double.parseDouble(s); + if (minimumTPS < 0.0) { + return AnvilGUI.Response.text(ColorUtil.translate(Config.MUST_BE_POSITIVE)); + } + else { + Config.MINIMUM_TPS.remove(checkName); + Config.MINIMUM_TPS.put(checkName, minimumTPS); + Config.setValue(path + "minimum-tps", minimumTPS); + player.sendMessage(ColorUtil.translate(Config.SET_MINIMUM_TPS.replaceAll("%check%", checkName).replaceAll("%value%", Double.toString(minimumTPS)))); + Bukkit.getScheduler().scheduleSyncDelayedTask(Vulcan.INSTANCE.getPlugin(), () -> ManageCheck.getInstance().open(player, check), 2L); + return AnvilGUI.Response.close(); + } + } + }).text("Current Value: " + defaultMinimumTPS).item(XMaterial.PAPER.parseItem()).plugin(Vulcan.INSTANCE.getPlugin()).open(player); + } + else if (item.equals(ManageCheck.getInstance().getRandomRotationIntervalItem())) { + if (ServerUtil.isHigherThan1_17()) { + player.sendMessage(ColorUtil.translate("&cThis is unavailable on 1.17 servers!")); + return; + } + final int defaultRotationInterval = Config.RANDOM_ROTATION_EVERY.get(checkName); + new AnvilGUI.Builder().onComplete((player1, s) -> { + if (!NumberUtils.isNumber(s) || s.contains(".")) { + return AnvilGUI.Response.text(ColorUtil.translate(Config.MUST_BE_AN_INTEGER)); + } + else { + final int randomRotationInterval = Integer.parseInt(s); + if (randomRotationInterval < 0) { + return AnvilGUI.Response.text(ColorUtil.translate(Config.MUST_BE_POSITIVE)); + } + else { + Config.RANDOM_ROTATION_EVERY.remove(checkName); + Config.RANDOM_ROTATION_EVERY.put(checkName, randomRotationInterval); + Config.setValue(path + "random-rotation.rotate-every", randomRotationInterval); + player.sendMessage(ColorUtil.translate(Config.SET_RANDOM_ROTATION_INTERVAL.replaceAll("%check%", checkName).replaceAll("%value%", Integer.toString(randomRotationInterval)))); + Bukkit.getScheduler().scheduleSyncDelayedTask(Vulcan.INSTANCE.getPlugin(), () -> ManageCheck.getInstance().open(player, check), 2L); + return AnvilGUI.Response.close(); + } + } + }).text("Current Value: " + defaultRotationInterval).item(XMaterial.PAPER.parseItem()).plugin(Vulcan.INSTANCE.getPlugin()).open(player); + } + else if (item.equals(ManageCheck.getInstance().getAlertIntervalItem())) { + if (ServerUtil.isHigherThan1_17()) { + player.sendMessage(ColorUtil.translate("&cThis is unavailable on 1.17 servers!")); + return; + } + final int defaultAlertInterval = Config.ALERT_INTERVAL.get(checkName); + new AnvilGUI.Builder().onComplete((player1, s) -> { + if (!NumberUtils.isNumber(s) || s.contains(".") || s.contains(",")) { + return AnvilGUI.Response.text(ColorUtil.translate(Config.MUST_BE_AN_INTEGER)); + } + else { + final int alertInterval = Integer.parseInt(s); + if (alertInterval < 0) { + return AnvilGUI.Response.text(ColorUtil.translate(Config.MUST_BE_POSITIVE)); + } + else { + Config.ALERT_INTERVAL.remove(checkName); + Config.ALERT_INTERVAL.put(checkName, alertInterval); + Config.setValue(path + "alert-interval", alertInterval); + player.sendMessage(ColorUtil.translate(Config.SET_ALERT_INTERVAL.replaceAll("%check%", checkName).replaceAll("%value%", Integer.toString(alertInterval)))); + Bukkit.getScheduler().scheduleSyncDelayedTask(Vulcan.INSTANCE.getPlugin(), () -> ManageCheck.getInstance().open(player, check), 2L); + return AnvilGUI.Response.close(); + } + } + }).text("Current Value: " + defaultAlertInterval).item(XMaterial.PAPER.parseItem()).plugin(Vulcan.INSTANCE.getPlugin()).open(player); + } + else if (item.equals(ManageCheck.getInstance().getBufferMultipleItem())) { + if (ServerUtil.isHigherThan1_17()) { + player.sendMessage(ColorUtil.translate("&cThis is unavailable on 1.17 servers!")); + return; + } + final double defaultBufferMultiple = Config.BUFFER_MULTIPLES.get(checkName); + new AnvilGUI.Builder().onComplete((player1, s) -> { + if (!NumberUtils.isNumber(s)) { + return AnvilGUI.Response.text(ColorUtil.translate(Config.MUST_BE_NUMBER)); + } + else { + final double bufferMultiple = Double.parseDouble(s); + if (bufferMultiple < 0.0) { + return AnvilGUI.Response.text("Must be positive!"); + } + else { + Config.BUFFER_MULTIPLES.remove(checkName); + Config.BUFFER_MULTIPLES.put(checkName, bufferMultiple); + Config.setValue(path + "buffer.multiple", bufferMultiple); + player.sendMessage(ColorUtil.translate(Config.SET_BUFFER_MULTIPLE.replaceAll("%check%", checkName).replaceAll("%value%", Double.toString(bufferMultiple)))); + Bukkit.getScheduler().scheduleSyncDelayedTask(Vulcan.INSTANCE.getPlugin(), () -> ManageCheck.getInstance().open(player, check), 2L); + return AnvilGUI.Response.close(); + } + } + }).text("Current Value: " + defaultBufferMultiple).item(XMaterial.PAPER.parseItem()).plugin(Vulcan.INSTANCE.getPlugin()).open(player); + } + else if (item.equals(ManageCheck.getInstance().getBufferDecayItem())) { + if (ServerUtil.isHigherThan1_17()) { + player.sendMessage(ColorUtil.translate("&cThis is unavailable on 1.17 servers!")); + return; + } + final double defaultBufferDecay = Config.BUFFER_DECAYS.get(checkName); + new AnvilGUI.Builder().onComplete((player1, s) -> { + if (!NumberUtils.isNumber(s)) { + return AnvilGUI.Response.text(ColorUtil.translate(Config.MUST_BE_NUMBER)); + } + else { + final double bufferDecay = Double.parseDouble(s); + if (bufferDecay < 0.0) { + return AnvilGUI.Response.text(ColorUtil.translate(Config.MUST_BE_NUMBER)); + } + else { + Config.BUFFER_DECAYS.remove(checkName); + Config.BUFFER_DECAYS.put(checkName, bufferDecay); + Config.setValue(path + "buffer.decay", bufferDecay); + player.sendMessage(ColorUtil.translate(Config.SET_BUFFER_DECAY.replaceAll("%check%", checkName).replaceAll("%value%", Double.toString(bufferDecay)))); + Bukkit.getScheduler().scheduleSyncDelayedTask(Vulcan.INSTANCE.getPlugin(), () -> ManageCheck.getInstance().open(player, check), 2L); + return AnvilGUI.Response.close(); + } + } + }).text("Current Value: " + defaultBufferDecay).item(XMaterial.PAPER.parseItem()).plugin(Vulcan.INSTANCE.getPlugin()).open(player); + } + else if (item.equals(ManageCheck.getInstance().getMaxViolationsItem())) { + if (ServerUtil.isHigherThan1_17()) { + player.sendMessage(ColorUtil.translate("&cThis is unavailable on 1.17 servers!")); + return; + } + final int defaultMaxViolations = Config.MAX_VIOLATIONS.get(checkName); + new AnvilGUI.Builder().onComplete((player1, s) -> { + if (!NumberUtils.isNumber(s) || s.contains(".")) { + return AnvilGUI.Response.text(ColorUtil.translate(Config.MUST_BE_AN_INTEGER)); + } + else { + final int maxViolations = Integer.parseInt(s); + if (maxViolations < 0) { + return AnvilGUI.Response.text(ColorUtil.translate(Config.MUST_BE_POSITIVE)); + } + else { + Config.MAX_VIOLATIONS.remove(checkName); + Config.MAX_VIOLATIONS.put(checkName, maxViolations); + Config.setValue(path + "max-violations", maxViolations); + player.sendMessage(ColorUtil.translate(Config.SET_MAX_VIOLATIONS.replaceAll("%check%", checkName).replaceAll("%value%", Double.toString(maxViolations)))); + Bukkit.getScheduler().scheduleSyncDelayedTask(Vulcan.INSTANCE.getPlugin(), () -> ManageCheck.getInstance().open(player, check), 2L); + return AnvilGUI.Response.close(); + } + } + }).text("Current Value: " + defaultMaxViolations).item(XMaterial.PAPER.parseItem()).plugin(Vulcan.INSTANCE.getPlugin()).open(player); + } + else if (item.equals(ManageCheck.getInstance().getMinimumViolationsToAlertItem())) { + if (ServerUtil.isHigherThan1_17()) { + player.sendMessage(ColorUtil.translate("&cThis is unavailable on 1.17 servers!")); + return; + } + final int defaultMinVlToNotify = Config.MINIMUM_VL_TO_NOTIFY.get(checkName); + new AnvilGUI.Builder().onComplete((player1, s) -> { + if (!NumberUtils.isNumber(s) || s.contains(".")) { + return AnvilGUI.Response.text(ColorUtil.translate(Config.MUST_BE_AN_INTEGER)); + } + else { + final int minVlToAlert = Integer.parseInt(s); + if (minVlToAlert < 0) { + return AnvilGUI.Response.text(ColorUtil.translate(Config.MUST_BE_AN_INTEGER)); + } + else { + Config.MINIMUM_VL_TO_NOTIFY.remove(checkName); + Config.MINIMUM_VL_TO_NOTIFY.put(checkName, minVlToAlert); + Config.setValue(path + "dont-alert-until", minVlToAlert); + player.sendMessage(ColorUtil.translate(Config.SET_MINIMUM_VIOLATIONS_TO_ALERT.replaceAll("%check%", checkName).replaceAll("%value%", Double.toString(minVlToAlert)))); + Bukkit.getScheduler().scheduleSyncDelayedTask(Vulcan.INSTANCE.getPlugin(), () -> ManageCheck.getInstance().open(player, check), 2L); + return AnvilGUI.Response.close(); + } + } + }).text("Current Value: " + defaultMinVlToNotify).item(XMaterial.PAPER.parseItem()).plugin(Vulcan.INSTANCE.getPlugin()).open(player); + } + else if (item.equals(ManageCheck.getInstance().getPunishmentCommandItem())) { + final List punishmentCommands = Config.PUNISHMENT_COMMANDS.get(checkName); + switch (event.getClick()) { + case LEFT: { + player.closeInventory(); + player.sendMessage(ColorUtil.translate(Config.ENTER_PUNISHMENT_COMMAND)); + this.addingPunishmentCommands.put(player.getUniqueId(), checkName); + this.configPath.put(player.getUniqueId(), path); + break; + } + case RIGHT: { + player.closeInventory(); + player.sendMessage(ColorUtil.translate("&7&m---»--*---------------------------------*--«---")); + player.sendMessage(ColorUtil.translate(Config.REMOVE_PUNISHMENT_COMMAND)); + player.sendMessage(ColorUtil.translate("&r")); + this.removingPunishmentCommands.put(player.getUniqueId(), checkName); + this.configPath.put(player.getUniqueId(), path); + for (int i = 0; i < punishmentCommands.size(); ++i) { + String command = punishmentCommands.get(i); + command = ColorUtil.translate(command); + player.sendMessage(ColorUtil.translate(" &8» &c" + i + " &8- &7" + ChatColor.stripColor(command))); + } + player.sendMessage(ColorUtil.translate("&7&m---»--*---------------------------------*--«---")); + break; + } + } + } + else if (item.equals(ManageCheck.getInstance().getGoBackItem())) { + final String s = checkCategory; + switch (s) { + case "combat": { + CombatChecks.getInstance().open(player, CombatChecks.getInstance().getCurrentPage().get(player.getUniqueId())); + break; + } + case "movement": { + MovementChecks.getInstance().open(player, MovementChecks.getInstance().getCurrentPage().get(player.getUniqueId())); + break; + } + case "player": { + PlayerChecks.getInstance().open(player, PlayerChecks.getInstance().getCurrentPage().get(player.getUniqueId())); + break; + } + } + } + } + } + + @EventHandler + public void onChat(final AsyncPlayerChatEvent event) { + final Player player = event.getPlayer(); + final String message = event.getMessage(); + Class check = null; + if (this.addingPunishmentCommands.containsKey(player.getUniqueId())) { + final String checkName = this.addingPunishmentCommands.get(player.getUniqueId()); + boolean stopped = false; + if (message.equals("CANCEL") || message.equals("STOP")) { + player.sendMessage(ColorUtil.translate(Config.STOPPED_EDITING_PUNISHMENT_COMMANDS)); + stopped = true; + } + else { + final List punishmentCommands = Config.PUNISHMENT_COMMANDS.get(checkName); + punishmentCommands.add(message); + Config.PUNISHMENT_COMMANDS.remove(checkName); + Config.PUNISHMENT_COMMANDS.put(checkName, punishmentCommands); + Config.setValue(this.configPath.get(player.getUniqueId()) + "punishment-commands", punishmentCommands); + } + for (int length = CheckManager.CHECKS.length, i = 0; i < length; ++i) { + if (check.getSimpleName().equals(checkName)) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> ManageCheck.getInstance().open(player, check)); + } + } + if (!stopped) { + player.sendMessage(ColorUtil.translate(Config.ADDED_PUNISHMENT_COMMAND.replaceAll("%command%", message).replaceAll("%check%", checkName))); + } + event.setCancelled(true); + this.removeFromLists(player); + } + if (this.removingPunishmentCommands.containsKey(player.getUniqueId())) { + final String checkName = this.removingPunishmentCommands.get(player.getUniqueId()); + if (message.equals("CANCEL") || message.equals("STOP")) { + player.sendMessage(ColorUtil.translate(Config.STOPPED_EDITING_PUNISHMENT_COMMANDS)); + } + else if (!this.isNumeric(message)) { + player.sendMessage(ColorUtil.translate(Config.MUST_BE_NUMBER)); + } + else { + final List punishmentCommands2 = Config.PUNISHMENT_COMMANDS.get(checkName); + final int index = Integer.parseInt(message); + if (index < 0 || index > punishmentCommands2.size()) { + player.sendMessage(ColorUtil.translate(Config.INVALID_INDEX_NUMBER)); + } + else { + final String removed = punishmentCommands2.get(index); + player.sendMessage(ColorUtil.translate(Config.REMOVED_PUNISHMENT_COMMAND.replaceAll("%command%", removed).replaceAll("%check%", checkName))); + punishmentCommands2.remove(index); + Config.PUNISHMENT_COMMANDS.remove(checkName); + Config.PUNISHMENT_COMMANDS.put(checkName, punishmentCommands2); + event.setCancelled(true); + Config.setValue(this.configPath.get(player.getUniqueId()) + "punishment-commands", punishmentCommands2); + for (final Class check2 : CheckManager.CHECKS) { + if (check2.getSimpleName().equals(checkName)) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> ManageCheck.getInstance().open(player, check2)); + } + } + } + } + this.removeFromLists(player); + } + } + + public void removeFromLists(final Player player) { + this.removingPunishmentCommands.remove(player.getUniqueId()); + this.addingPunishmentCommands.remove(player.getUniqueId()); + this.configPath.remove(player.getUniqueId()); + } + + private boolean isNumeric(final String s) { + for (final char c : s.toCharArray()) { + if (!Character.isDigit(c)) { + return false; + } + } + return true; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/hook/brewery/BreweryHook.java b/src/main/java/me/frep/vulcan/spigot/hook/brewery/BreweryHook.java new file mode 100644 index 0000000..974c929 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/hook/brewery/BreweryHook.java @@ -0,0 +1,21 @@ +package me.frep.vulcan.spigot.hook.brewery; + +import org.bukkit.event.EventHandler; +import me.frep.vulcan.spigot.data.PlayerData; +import org.bukkit.entity.Player; +import me.frep.vulcan.spigot.Vulcan; +import com.dre.brewery.api.events.PlayerPushEvent; +import org.bukkit.event.Listener; + +public class BreweryHook implements Listener +{ + @EventHandler + public void onPush(final PlayerPushEvent event) { + final Player player = event.getPlayer(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + data.getActionProcessor().setSincePushTicks(0); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/hook/crackshot/CrackShotHook.java b/src/main/java/me/frep/vulcan/spigot/hook/crackshot/CrackShotHook.java new file mode 100644 index 0000000..5802005 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/hook/crackshot/CrackShotHook.java @@ -0,0 +1,22 @@ +package me.frep.vulcan.spigot.hook.crackshot; + +import org.bukkit.event.EventHandler; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.entity.Player; +import com.shampaggon.crackshot.events.WeaponDamageEntityEvent; +import org.bukkit.event.Listener; + +public class CrackShotHook implements Listener +{ + @EventHandler + public void onDamage(final WeaponDamageEntityEvent event) { + if (event.getVictim() instanceof Player) { + final Player player = (Player)event.getVictim(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data != null) { + data.getActionProcessor().handleCrackshotDamage(); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/hook/discord/DiscordHelper.java b/src/main/java/me/frep/vulcan/spigot/hook/discord/DiscordHelper.java new file mode 100644 index 0000000..ac13e5a --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/hook/discord/DiscordHelper.java @@ -0,0 +1,177 @@ +package me.frep.vulcan.spigot.hook.discord; + +import java.util.logging.Level; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.Color; +import me.frep.vulcan.spigot.util.ColorUtil; +import me.frep.vulcan.spigot.util.ServerUtil; +import java.text.DecimalFormat; +import me.frep.vulcan.spigot.config.Stats; +import me.frep.vulcan.spigot.util.PlayerUtil; +import java.util.Iterator; +import java.time.temporal.TemporalAccessor; +import java.util.Date; +import java.util.Collection; +import java.util.ArrayList; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.entities.TextChannel; +import me.joshb.discordbotapi.server.DiscordBotAPI; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.AbstractCheck; +import org.bukkit.Bukkit; +import me.frep.vulcan.spigot.config.Config; +import java.util.List; + +public class DiscordHelper +{ + public static String COMMAND_PREFIX; + public static String ALERTS_CHANNEL_ID; + public static String PUNISHMENT_CHANNEL_ID; + public static String ALERTS_FORMAT_COLOR; + public static String PUNISHMENT_FORMAT_COLOR; + public static String ALERTS_FORMAT_TITLE; + public static String PUNISHMENT_FORMAT_TITLE; + public static String ALERTS_FORMAT_DESCRIPTION; + public static String PUNISHMENT_FORMAT_DESCRIPTION; + public static String ALERTS_FORMAT_IMAGE; + public static String PUNISHMENT_FORMAT_IMAGE; + public static String ALERTS_FORMAT_FOOTER; + public static String PUNISHMENT_FORMAT_FOOTER; + private static List ALERTS_FORMAT_CONTENT; + private static List PUNISHMENT_FORMAT_CONTENT; + private static DiscordHelper instance; + + public DiscordHelper() { + (DiscordHelper.instance = this).updateConfig(); + } + + public void updateConfig() { + try { + DiscordHelper.ALERTS_CHANNEL_ID = Config.getString("hooks.discord.alerts-channel-id"); + DiscordHelper.PUNISHMENT_CHANNEL_ID = Config.getString("hooks.discord.punishment-channel-id"); + DiscordHelper.COMMAND_PREFIX = Config.getString("hooks.discord.command-prefix"); + DiscordHelper.ALERTS_FORMAT_COLOR = Config.getString("hooks.discord.alerts-format.color"); + DiscordHelper.ALERTS_FORMAT_TITLE = Config.getString("hooks.discord.alerts-format.title"); + DiscordHelper.ALERTS_FORMAT_DESCRIPTION = Config.getString("hooks.discord.alerts-format.description"); + DiscordHelper.ALERTS_FORMAT_IMAGE = Config.getString("hooks.discord.alerts-format.image"); + DiscordHelper.ALERTS_FORMAT_CONTENT = Config.getStringList("hooks.discord.alerts-format.content"); + DiscordHelper.ALERTS_FORMAT_FOOTER = Config.getString("hooks.discord.alerts-format.footer"); + DiscordHelper.PUNISHMENT_FORMAT_COLOR = Config.getString("hooks.discord.punishment-format.color"); + DiscordHelper.PUNISHMENT_FORMAT_TITLE = Config.getString("hooks.discord.punishment-format.title"); + DiscordHelper.PUNISHMENT_FORMAT_DESCRIPTION = Config.getString("hooks.discord.punishment-format.description"); + DiscordHelper.PUNISHMENT_FORMAT_IMAGE = Config.getString("hooks.discord.punishment-format.image"); + DiscordHelper.PUNISHMENT_FORMAT_CONTENT = Config.getStringList("hooks.discord.punishment-format.content"); + DiscordHelper.PUNISHMENT_FORMAT_FOOTER = Config.getString("hooks.discord.punishment-format.footer"); + } + catch (final Exception e) { + Bukkit.getLogger().severe("Error while loading Vulcan's configuration file!"); + e.printStackTrace(); + } + } + + public void sendDiscordAlertMessage(final AbstractCheck check, final PlayerData playerData, final String info) { + if (DiscordHelper.ALERTS_CHANNEL_ID.equals("channel_id_here") || !Config.getBoolean("hooks.discord.enable-hook")) { + return; + } + final TextChannel textChannel = DiscordBotAPI.getJDA().getTextChannelById(DiscordHelper.ALERTS_CHANNEL_ID); + textChannel.sendMessage(this.getAlertMessage(check, playerData, info)).queue(); + } + + public void sendDiscordPunishMessage(final AbstractCheck check, final PlayerData playerData) { + if (DiscordHelper.PUNISHMENT_CHANNEL_ID.equals("channel_id_here") || !Config.getBoolean("hooks.discord.enable-hook")) { + return; + } + final TextChannel textChannel = DiscordBotAPI.getJDA().getTextChannelById(DiscordHelper.PUNISHMENT_CHANNEL_ID); + textChannel.sendMessage(this.getPunishmentMessage(check, playerData)).queue(); + } + + private MessageEmbed getAlertMessage(final AbstractCheck check, final PlayerData playerData, final String info) { + final EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(this.getColor(true)); + embedBuilder.setTitle(this.formatAlert(DiscordHelper.ALERTS_FORMAT_TITLE, check, playerData, info)); + embedBuilder.setDescription(this.formatAlert(DiscordHelper.ALERTS_FORMAT_DESCRIPTION, check, playerData, info)); + embedBuilder.setThumbnail(this.formatAlert(DiscordHelper.ALERTS_FORMAT_IMAGE, check, playerData, info)); + final List formatContent = new ArrayList(DiscordHelper.ALERTS_FORMAT_CONTENT); + for (final String content : formatContent) { + final String[] contentSplit = content.split("\\|"); + if (content.startsWith("break")) { + final boolean b = Boolean.parseBoolean(contentSplit[1]); + embedBuilder.addBlankField(b); + } + else { + final String value = this.formatAlert(contentSplit[1], check, playerData, info); + final boolean b2 = Boolean.parseBoolean(contentSplit[2]); + embedBuilder.addField(contentSplit[0], value, b2); + } + } + embedBuilder.setTimestamp(new Date().toInstant()); + return embedBuilder.build(); + } + + private MessageEmbed getPunishmentMessage(final AbstractCheck check, final PlayerData playerData) { + final EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(this.getColor(false)); + embedBuilder.setTitle(this.formatPunishment(DiscordHelper.PUNISHMENT_FORMAT_TITLE, check, playerData)); + embedBuilder.setDescription(this.formatPunishment(DiscordHelper.PUNISHMENT_FORMAT_DESCRIPTION, check, playerData)); + embedBuilder.setThumbnail(this.formatPunishment(DiscordHelper.PUNISHMENT_FORMAT_IMAGE, check, playerData)); + final List formatContent = new ArrayList(DiscordHelper.PUNISHMENT_FORMAT_CONTENT); + for (final String content : formatContent) { + final String[] contentSplit = content.split("\\|"); + if (content.startsWith("break")) { + final boolean b = Boolean.parseBoolean(contentSplit[1]); + embedBuilder.addBlankField(b); + } + else { + final String value = this.formatPunishment(contentSplit[1], check, playerData); + final boolean b2 = Boolean.parseBoolean(contentSplit[2]); + embedBuilder.addField(contentSplit[0], value, b2); + } + } + embedBuilder.setTimestamp(new Date().toInstant()); + return embedBuilder.build(); + } + + private String formatAlert(final String string, final AbstractCheck check, final PlayerData data, final String info) { + return string.replaceAll("%player%", data.getPlayer().getName()).replaceAll("%client-version%", PlayerUtil.getClientVersionToString(data.getPlayer())).replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%info%", info).replaceAll("%max-vl%", Integer.toString(check.getMaxVl())).replaceAll("%world%", data.getPlayer().getWorld().getName()).replaceAll("%total-punishments%", Integer.toString(Stats.getPunishments())).replaceAll("%server-name%", Config.SERVER_NAME).replaceAll("%complex-type%", check.getCheckInfo().complexType()).replaceAll("%x%", Integer.toString(data.getPlayer().getLocation().getBlockX())).replaceAll("%y%", Integer.toString(data.getPlayer().getLocation().getBlockY())).replaceAll("%z%", Integer.toString(data.getPlayer().getLocation().getBlockZ())).replaceAll("%uuid%", data.getPlayer().getUniqueId().toString()).replaceAll("%check%", check.getCheckInfo().name()).replaceAll("%tps%", new DecimalFormat("##.##").format(ServerUtil.getTPS())).replaceAll("%ping%", String.valueOf(PlayerUtil.getPing(data.getPlayer()))).replaceAll("%dev%", check.getCheckInfo().experimental() ? ColorUtil.translate("*") : "").replaceAll("%vl%", Integer.toString(check.getVl())).replaceAll("%type%", Character.toString(check.getCheckInfo().type())); + } + + private String formatPunishment(final String string, final AbstractCheck check, final PlayerData data) { + return string.replaceAll("%player%", data.getPlayer().getName()).replaceAll("%client-version%", PlayerUtil.getClientVersionToString(data.getPlayer())).replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%world%", data.getPlayer().getWorld().getName()).replaceAll("%server-name%", Config.SERVER_NAME).replaceAll("%complex-type%", check.getCheckInfo().complexType()).replaceAll("%total-punishments%", Integer.toString(Stats.getPunishments())).replaceAll("%max-vl%", Integer.toString(check.getMaxVl())).replaceAll("%x%", Integer.toString(data.getPlayer().getLocation().getBlockX())).replaceAll("%y%", Integer.toString(data.getPlayer().getLocation().getBlockY())).replaceAll("%z%", Integer.toString(data.getPlayer().getLocation().getBlockZ())).replaceAll("%uuid%", data.getPlayer().getUniqueId().toString()).replaceAll("%check%", check.getCheckInfo().name()).replaceAll("%tps%", new DecimalFormat("##.##").format(ServerUtil.getTPS())).replaceAll("%ping%", String.valueOf(PlayerUtil.getPing(data.getPlayer()))).replaceAll("%dev%", check.getCheckInfo().experimental() ? ColorUtil.translate("*") : "").replaceAll("%vl%", Integer.toString(check.getVl())).replaceAll("%type%", Character.toString(check.getCheckInfo().type())); + } + + private int getColor(final boolean alerts) { + final int color = Color.BLACK.asRGB(); + String mode; + if (alerts) { + mode = "hooks.discord.alerts-format.color"; + } + else { + mode = "hooks.discord.punishment-format.color"; + } + try { + if (Config.isColor(mode)) { + return Config.getColor(mode).asRGB(); + } + if (Config.isString(mode)) { + final String colorString = Config.getString(mode); + try { + return java.awt.Color.decode(colorString).getRGB(); + } + catch (final Exception ignored) { + final Color c = (Color)Class.forName("org.bukkit.Color").getField(colorString).get(null); + return c.asRGB(); + } + } + return Config.getInt(mode); + } + catch (final ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) { + Vulcan.INSTANCE.getPlugin().getLogger().log(Level.SEVERE, "Error while parsing color for discord hook!"); + return color; + } + } + + public static DiscordHelper getInstance() { + return DiscordHelper.instance; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/hook/gsit/GSitListener.java b/src/main/java/me/frep/vulcan/spigot/hook/gsit/GSitListener.java new file mode 100644 index 0000000..165c9e4 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/hook/gsit/GSitListener.java @@ -0,0 +1,32 @@ +package me.frep.vulcan.spigot.hook.gsit; + +import dev.geco.gsit.api.event.PlayerGetUpCrawlEvent; +import dev.geco.gsit.api.event.PlayerCrawlEvent; +import org.bukkit.event.EventHandler; +import me.frep.vulcan.spigot.data.PlayerData; +import org.bukkit.entity.Player; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.event.Listener; + +public class GSitListener implements Listener +{ + @EventHandler + public void onCrawl(final PlayerCrawlEvent event) { + final Player player = event.getPlayer(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + data.getActionProcessor().setCrawling(true); + } + + @EventHandler + public void onCrawl(final PlayerGetUpCrawlEvent event) { + final Player player = event.getPlayer(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + data.getActionProcessor().setCrawling(false); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/hook/mcmmo/McMMOHook.java b/src/main/java/me/frep/vulcan/spigot/hook/mcmmo/McMMOHook.java new file mode 100644 index 0000000..c877573 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/hook/mcmmo/McMMOHook.java @@ -0,0 +1,35 @@ +package me.frep.vulcan.spigot.hook.mcmmo; + +import com.gmail.nossr50.datatypes.skills.AbilityType; +import com.gmail.nossr50.events.skills.abilities.McMMOPlayerAbilityDeactivateEvent; +import org.bukkit.event.EventHandler; +import me.frep.vulcan.spigot.data.PlayerData; +import org.bukkit.entity.Player; +import me.frep.vulcan.spigot.Vulcan; +import com.gmail.nossr50.events.skills.abilities.McMMOPlayerAbilityActivateEvent; +import org.bukkit.event.Listener; + +public class McMMOHook implements Listener +{ + @EventHandler + public void onActivate(final McMMOPlayerAbilityActivateEvent event) { + final Player player = event.getPlayer(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data != null) { + if (event.getAbility() == AbilityType.BERSERK) { + data.getActionProcessor().setBerserking(true); + } + } + } + + @EventHandler + public void onDeactivate(final McMMOPlayerAbilityDeactivateEvent event) { + final Player player = event.getPlayer(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data != null) { + if (event.getAbility() == AbilityType.BERSERK) { + data.getActionProcessor().setBerserking(false); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/hook/mythicmobs/MythicMobsHook.java b/src/main/java/me/frep/vulcan/spigot/hook/mythicmobs/MythicMobsHook.java new file mode 100644 index 0000000..4d3d03f --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/hook/mythicmobs/MythicMobsHook.java @@ -0,0 +1,29 @@ +package me.frep.vulcan.spigot.hook.mythicmobs; + +import org.bukkit.event.EventHandler; +import me.frep.vulcan.spigot.data.PlayerData; +import io.lumine.xikage.mythicmobs.MythicMobs; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.Listener; + +public class MythicMobsHook implements Listener +{ + @EventHandler + public void onDamage(final EntityDamageByEntityEvent event) { + if (!(event.getEntity() instanceof Player)) { + return; + } + final Player player = (Player)event.getEntity(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + if (!Vulcan.INSTANCE.isMythicMobsLatest()) { + if (MythicMobs.inst().getAPIHelper().isMythicMob(event.getDamager())) { + data.getActionProcessor().setSinceMythicMobTicks(0); + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/hook/placeholderapi/PlaceholderAPIExtension.java b/src/main/java/me/frep/vulcan/spigot/hook/placeholderapi/PlaceholderAPIExtension.java new file mode 100644 index 0000000..3e6fd70 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/hook/placeholderapi/PlaceholderAPIExtension.java @@ -0,0 +1,73 @@ +package me.frep.vulcan.spigot.hook.placeholderapi; + +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.config.Stats; +import org.bukkit.entity.Player; +import me.frep.vulcan.spigot.Vulcan; +import me.frep.vulcan.spigot.VulcanPlugin; +import me.clip.placeholderapi.expansion.PlaceholderExpansion; + +public class PlaceholderAPIExtension extends PlaceholderExpansion +{ + private final VulcanPlugin plugin; + + public PlaceholderAPIExtension() { + this.plugin = Vulcan.INSTANCE.getPlugin(); + } + + public boolean persist() { + return true; + } + + public boolean canRegister() { + return true; + } + + public String getAuthor() { + return this.plugin.getDescription().getAuthors().toString(); + } + + public String getIdentifier() { + return "Vulcan"; + } + + public String getVersion() { + return this.plugin.getDescription().getVersion(); + } + + public String onPlaceholderRequest(final Player player, final String identifier) { + if (player == null) { + return ""; + } + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return ""; + } + switch (identifier) { + case "cps": { + return Double.toString(data.getClickProcessor().getCps()); + } + case "total_violations": { + return Integer.toString(data.getTotalViolations()); + } + case "combat_violations": { + return Integer.toString(data.getCombatViolations()); + } + case "movement_violations": { + return Integer.toString(data.getMovementViolations()); + } + case "player_violations": { + return Integer.toString(data.getPlayerViolations()); + } + case "client_brand": { + return data.getClientBrand(); + } + case "total_punishments": { + return Integer.toString(Stats.getPunishments()); + } + default: { + return null; + } + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/id/ID.java b/src/main/java/me/frep/vulcan/spigot/id/ID.java new file mode 100644 index 0000000..9aa3bda --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/id/ID.java @@ -0,0 +1,16 @@ +package me.frep.vulcan.spigot.id; + +public class ID +{ + public static String spigot() { + return "HALAL 5170 EDITION"; + } + + public static String nonce() { + return "LICENSED TO: NIGGAS FROM THE HOOD"; + } + + public static String resource() { + return "%%__RESOURCE__%%"; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/jday/JDay.java b/src/main/java/me/frep/vulcan/spigot/jday/JDay.java new file mode 100644 index 0000000..2248b6e --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/jday/JDay.java @@ -0,0 +1,90 @@ +package me.frep.vulcan.spigot.jday; + +import org.bukkit.entity.Player; +import java.util.Iterator; +import me.frep.vulcan.api.event.VulcanJudgementDayEndEvent; +import org.bukkit.plugin.Plugin; +import java.util.function.Consumer; +import me.frep.vulcan.spigot.util.ServerUtil; +import org.bukkit.event.Event; +import me.frep.vulcan.api.event.VulcanJudgementDayStartEvent; +import org.bukkit.Bukkit; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.jday.config.JDayConfig; +import me.frep.vulcan.spigot.Vulcan; + +public class JDay +{ + public static void executeBanWave() { + Vulcan.INSTANCE.getJudgementExecutor().execute(() -> { + final JDayConfig pending = new JDayConfig("jday-pending"); + final JDayConfig banned = new JDayConfig("jday-banned"); + if (pending.getConfigFile().getConfigurationSection("PendingUsers") != null && pending.getConfigFile().getConfigurationSection("PendingUsers").getKeys(false) != null) { + if (Config.ENABLE_API) { + Bukkit.getPluginManager().callEvent(new VulcanJudgementDayStartEvent()); + } + Config.JDAY_STARTED_BROADCAST.forEach(ServerUtil::broadcast); + int total = 0; + Iterator iterator = pending.getConfigFile().getConfigurationSection("PendingUsers").getKeys(false).iterator(); + while (iterator.hasNext()) { + final String string = iterator.next(); + final String name = pending.getConfigFile().getString("PendingUsers." + string + ".Name"); + final String uuid = pending.getConfigFile().getString("PendingUsers." + string + ".UUID"); + final String reason = pending.getConfigFile().getString("PendingUsers." + string + ".Reason"); + final String executedBy = pending.getConfigFile().getString("PendingUsers." + string + ".ExecutedBy"); + final String wasOnline = pending.getConfigFile().getString("PendingUsers." + string + ".wasOnline"); + final String date = pending.getConfigFile().getString("PendingUsers." + string + ".Date"); + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> Config.JDAY_COMMANDS.forEach(command -> ServerUtil.dispatchCommand(command.replaceAll("%player%", name)))); + Config.JDAY_BROADCAST.forEach(broadcast -> ServerUtil.broadcast(broadcast.replaceAll("%player%", name))); + banned.getConfigFile().set("BannedUsers." + string + ".Name", name); + banned.getConfigFile().set("BannedUsers." + string + ".UUID", uuid); + banned.getConfigFile().set("BannedUsers." + string + ".Date", date); + banned.getConfigFile().set("BannedUsers." + string + ".Reason", reason); + banned.getConfigFile().set("BannedUsers." + string + ".ExecutedBy", executedBy); + banned.getConfigFile().set("BannedUsers." + string + ".wasOnline", wasOnline); + banned.saveConfigFile(); + ++total; + try { + Thread.sleep(Config.JDAY_COOLDOWN); + } + catch (final InterruptedException e) { + e.printStackTrace(); + } + } + if (Config.ENABLE_API) { + Bukkit.getPluginManager().callEvent(new VulcanJudgementDayEndEvent()); + } + final int finalTotal = total; + Config.JDAY_END_BROADCAST.forEach(broadcast -> ServerUtil.broadcast(broadcast.replaceAll("%amount%", Integer.toString(finalTotal)))); + pending.getConfigFile().set("PendingUsers", null); + pending.saveConfigFile(); + Vulcan.INSTANCE.getPlugin().saveConfig(); + } + }); + } + + public static boolean isInBanWave(final Player player) { + final JDayConfig pending = new JDayConfig("jday-pending"); + if (pending.getConfigFile().getConfigurationSection("PendingUsers") == null) { + return false; + } + final Iterator iterator = pending.getConfigFile().getConfigurationSection("PendingUsers").getKeys(false).iterator(); + if (iterator.hasNext()) { + final String string = (String)iterator.next(); + return string.equalsIgnoreCase(player.getUniqueId().toString()); + } + return false; + } + + public static int getAmountToBan() { + final JDayConfig pending = new JDayConfig("jday-pending"); + int count = 0; + if (pending.getConfigFile().getConfigurationSection("PendingUsers") == null) { + return 0; + } + for (final String string : pending.getConfigFile().getConfigurationSection("PendingUsers").getKeys(false)) { + ++count; + } + return count; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/jday/config/JDayConfig.java b/src/main/java/me/frep/vulcan/spigot/jday/config/JDayConfig.java new file mode 100644 index 0000000..1d1886b --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/jday/config/JDayConfig.java @@ -0,0 +1,30 @@ +package me.frep.vulcan.spigot.jday.config; + +import org.bukkit.configuration.file.YamlConfiguration; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.configuration.file.FileConfiguration; +import java.io.File; + +public class JDayConfig +{ + private final File userFile; + private final FileConfiguration userConfig; + + public JDayConfig(final String name) { + this.userFile = new File(Vulcan.INSTANCE.getPlugin().getDataFolder() + File.separator, name + ".yml"); + this.userConfig = YamlConfiguration.loadConfiguration(this.userFile); + } + + public FileConfiguration getConfigFile() { + return this.userConfig; + } + + public void saveConfigFile() { + try { + this.getConfigFile().save(this.userFile); + } + catch (final Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/listener/PlayerListener.java b/src/main/java/me/frep/vulcan/spigot/listener/PlayerListener.java new file mode 100644 index 0000000..1d8b7f8 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/listener/PlayerListener.java @@ -0,0 +1,31 @@ +package me.frep.vulcan.spigot.listener; + +import org.bukkit.event.EventHandler; +import me.frep.vulcan.spigot.data.PlayerData; +import org.bukkit.entity.Player; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.util.ColorUtil; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.Listener; + +public class PlayerListener implements Listener +{ + @EventHandler + public void onQuit(final PlayerQuitEvent event) { + final Player player = event.getPlayer(); + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + if (data.getPositionProcessor().isFrozen()) { + Vulcan.INSTANCE.getAlertManager().sendMessage(Config.LOGGED_OUT_WHILE_FROZEN.replaceAll("%player%", player.getName())); + Config.LOGGED_OUT_FROZEN_COMMANDS.forEach(command -> ServerUtil.dispatchCommand(ColorUtil.translate(command.replaceAll("%player%", player.getName())))); + } + Vulcan.INSTANCE.getGuiManager().removeFromLists(player); + Vulcan.INSTANCE.getAlertManager().getAlertsEnabled().remove(player); + Vulcan.INSTANCE.getAlertManager().getVerboseEnabled().remove(player); + Vulcan.INSTANCE.getPlayerDataManager().remove(player); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/network/NetworkManager.java b/src/main/java/me/frep/vulcan/spigot/network/NetworkManager.java new file mode 100644 index 0000000..988707e --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/network/NetworkManager.java @@ -0,0 +1,73 @@ +package me.frep.vulcan.spigot.network; + +import io.github.retrooper.packetevents.event.impl.PlayerEjectEvent; +import io.github.retrooper.packetevents.utils.player.ClientVersion; +import org.bukkit.entity.Player; +import me.frep.vulcan.spigot.config.Config; +import io.github.retrooper.packetevents.event.impl.PostPlayerInjectEvent; +import io.github.retrooper.packetevents.event.impl.PacketPlaySendEvent; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.packet.Packet; +import io.github.retrooper.packetevents.packetwrappers.play.in.custompayload.WrappedPacketInCustomPayload; +import me.frep.vulcan.spigot.Vulcan; +import io.github.retrooper.packetevents.event.impl.PacketPlayReceiveEvent; +import io.github.retrooper.packetevents.event.priority.PacketEventPriority; +import io.github.retrooper.packetevents.event.PacketListenerAbstract; + +public class NetworkManager extends PacketListenerAbstract +{ + public NetworkManager(final PacketEventPriority priority) { + super(priority); + this.filterAll(); + this.addClientSidedPlayFilter((byte) -93, (byte) -96, (byte) -94, (byte) -95, (byte) -100, (byte) -71, (byte) -88, (byte) -103, (byte) -111, (byte) -108, (byte) -68, (byte) -69,(byte) -105,(byte) -104,(byte) -86,(byte) -87,(byte) -98, (byte) -85,(byte) -78,(byte) -110,(byte) -92,(byte) -70,(byte) -75, (byte) -107, (byte) 28); + this.addServerSidedPlayFilter((byte)-26,(byte) -13,(byte) -48,(byte) 3,(byte) -17,(byte) -3,(byte) -36,(byte) 23,(byte) -10,(byte) 27,(byte) -11,(byte) -23,(byte) -25,(byte) 29,(byte) 1,(byte) 22,(byte) -38); + } + + @Override + public void onPacketPlayReceive(final PacketPlayReceiveEvent event) { + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(event.getPlayer()); + if (data != null) { + if (event.getPacketId() == -103) { + final WrappedPacketInCustomPayload wrapper = new WrappedPacketInCustomPayload(event.getNMSPacket()); + if (wrapper.getChannelName().toLowerCase().contains("brand")) { + Vulcan.INSTANCE.getClientBrandManager().handle(data, wrapper.getData()); + } + } + Vulcan.INSTANCE.getPacketExecutor().execute(() -> Vulcan.INSTANCE.getReceivingPacketProcessor().handle(data, new Packet(Packet.Direction.RECEIVE, event.getNMSPacket(), event.getPacketId()))); + } + } + + @Override + public void onPacketPlaySend(final PacketPlaySendEvent event) { + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(event.getPlayer()); + if (data == null || (event.getPacketId() == -26 && (data.getCombatProcessor().getTrackedPlayer() == null || data.getCombatProcessor().getLastTrackedPlayer() == null))) { + return; + } + Vulcan.INSTANCE.getPacketExecutor().execute(() -> Vulcan.INSTANCE.getSendingPacketProcessor().handle(data, new Packet(Packet.Direction.SEND, event.getNMSPacket(), event.getPacketId()))); + } + + @Override + public void onPostPlayerInject(final PostPlayerInjectEvent event) { + final Player player = event.getPlayer(); + final boolean npc = player.hasMetadata("NPC") || player.hasMetadata("npc"); + if (!npc) { + Vulcan.INSTANCE.getPlayerDataManager().add(player); + } + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data == null) { + return; + } + final ClientVersion clientVersion = event.getClientVersion(); + data.setClientVersion(clientVersion); + if (player.hasPermission("vulcan.alerts") && Config.TOGGLE_ALERTS_ON_JOIN) { + Vulcan.INSTANCE.getAlertManager().toggleAlerts(player); + } + data.getPositionProcessor().onJoin(); + data.getActionProcessor().onJoin(); + } + + @Override + public void onPlayerEject(final PlayerEjectEvent event) { + Vulcan.INSTANCE.getPlayerDataManager().remove(event.getPlayer()); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/packet/Packet.java b/src/main/java/me/frep/vulcan/spigot/packet/Packet.java new file mode 100644 index 0000000..f0e7fd6 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/packet/Packet.java @@ -0,0 +1,219 @@ +package me.frep.vulcan.spigot.packet; + +import io.github.retrooper.packetevents.packettype.PacketType; +import io.github.retrooper.packetevents.packetwrappers.NMSPacket; + +public class Packet +{ + private final Direction direction; + private final NMSPacket rawPacket; + private final byte packetId; + + public Packet(final Direction direction, final NMSPacket rawPacket, final byte packetId) { + this.direction = direction; + this.rawPacket = rawPacket; + this.packetId = packetId; + } + + public boolean isReceiving() { + return this.direction == Direction.RECEIVE; + } + + public boolean isSending() { + return this.direction == Direction.SEND; + } + + public boolean isFlying() { + return this.isReceiving() && PacketType.Play.Client.Util.isInstanceOfFlying(this.packetId); + } + + public boolean isUseEntity() { + return this.isReceiving() && this.packetId == -100; + } + + public boolean isSpectate() { + return this.isReceiving() && this.packetId == -70; + } + + public boolean isPong() { + return this.isReceiving() && this.packetId == 28; + } + + public boolean isRotation() { + return this.isReceiving() && (this.packetId == -94 || this.packetId == -95); + } + + public boolean isPosition() { + return this.isReceiving() && (this.packetId == -96 || this.packetId == -95); + } + + public boolean isExplosion() { + return this.isSending() && this.packetId == -38; + } + + public boolean isArmAnimation() { + return this.isReceiving() && this.packetId == -71; + } + + public boolean isCreativeSlot() { + return this.isReceiving() && this.packetId == -75; + } + + public boolean isMetaData() { + return this.isSending() && this.packetId == 1; + } + + public boolean isAbilities() { + return this.isReceiving() && this.packetId == -88; + } + + public boolean isAbilitiesOut() { + return this.isSending() && this.packetId == -17; + } + + public boolean isHeldItemSlotOut() { + return this.isSending() && this.packetId == -3; + } + + public boolean isBlockPlaceEvent() { + return this.isReceiving() && this.packetId == 120; + } + + public boolean isCustomPayload() { + return this.isReceiving() && this.packetId == -103; + } + + public boolean isProjectileLaunchEvent() { + return this.isReceiving() && this.packetId == 98; + } + + public boolean isChat() { + return this.isReceiving() && this.packetId == -111; + } + + public boolean isItemConsumeEvent() { + return this.isReceiving() && this.packetId == 97; + } + + public boolean isTabComplete() { + return this.isReceiving() && this.packetId == -108; + } + + public boolean isInteractEvent() { + return this.isReceiving() && this.packetId == 96; + } + + public boolean isBlockPlace() { + return (this.isReceiving() && PacketType.Play.Client.Util.isBlockPlace(this.packetId)) || (this.isReceiving() && this.packetId == -68); + } + + public boolean isBlockDig() { + return this.isReceiving() && this.packetId == -87; + } + + public boolean isWindowClick() { + return this.isReceiving() && this.packetId == -105; + } + + public boolean isEntityAction() { + return this.isReceiving() && this.packetId == -86; + } + + public boolean isCloseWindow() { + return this.isReceiving() && this.packetId == -104; + } + + public boolean isUpdateAttributes() { + return this.isSending() && this.packetId == 22; + } + + public boolean isKeepAlive() { + return this.isReceiving() && this.packetId == -98; + } + + public boolean isSteerVehicle() { + return this.isReceiving() && this.packetId == -85; + } + + public boolean isHeldItemSlot() { + return this.isReceiving() && this.packetId == -78; + } + + public boolean isClientCommand() { + return this.isReceiving() && this.packetId == -110; + } + + public boolean isTransaction() { + return this.isReceiving() && this.packetId == -107; + } + + public boolean isSendTransaction() { + return this.isSending() && this.packetId == -48; + } + + public boolean isTeleport() { + return this.isSending() && this.packetId == -13; + } + + public boolean isVehicleMove() { + return this.isReceiving() && this.packetId == -92; + } + + public boolean isVelocity() { + return this.isSending() && this.packetId == 3; + } + + public boolean isPositionLook() { + return this.isReceiving() && this.packetId == -95; + } + + public boolean isRelEntityMove() { + return this.isSending() && this.packetId == -26; + } + + public boolean isRelEntityMoveLook() { + return this.isSending() && this.packetId == -25; + } + + public boolean isCreateEntity() { + return this.isSending() && this.packetId == 27; + } + + public boolean isDeleteEntity() { + return this.isSending() && this.packetId == -11; + } + + public boolean isBlockBreakEvent() { + return this.isReceiving() && this.packetId == 100; + } + + public boolean isEntityEffect() { + return this.isSending() && this.packetId == 23; + } + + public boolean isRemoveEntityEffect() { + return this.isSending() && this.packetId == -10; + } + + public boolean isGameStateChange() { + return this.isSending() && this.packetId == -36; + } + + public Direction getDirection() { + return this.direction; + } + + public NMSPacket getRawPacket() { + return this.rawPacket; + } + + public byte getPacketId() { + return this.packetId; + } + + public enum Direction + { + SEND, + RECEIVE; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/packet/processor/ReceivingPacketProcessor.java b/src/main/java/me/frep/vulcan/spigot/packet/processor/ReceivingPacketProcessor.java new file mode 100644 index 0000000..528cb78 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/packet/processor/ReceivingPacketProcessor.java @@ -0,0 +1,109 @@ +package me.frep.vulcan.spigot.packet.processor; + +import java.util.Iterator; +import me.frep.vulcan.spigot.check.AbstractCheck; +import io.github.retrooper.packetevents.packetwrappers.play.in.useentity.WrappedPacketInUseEntity; +import io.github.retrooper.packetevents.packetwrappers.play.in.transaction.WrappedPacketInTransaction; +import io.github.retrooper.packetevents.packetwrappers.play.in.pong.WrappedPacketInPong; +import io.github.retrooper.packetevents.packetwrappers.play.in.clientcommand.WrappedPacketInClientCommand; +import io.github.retrooper.packetevents.packetwrappers.play.in.vehiclemove.WrappedPacketInVehicleMove; +import io.github.retrooper.packetevents.packetwrappers.play.in.helditemslot.WrappedPacketInHeldItemSlot; +import io.github.retrooper.packetevents.packetwrappers.play.in.blockdig.WrappedPacketInBlockDig; +import io.github.retrooper.packetevents.packetwrappers.play.in.entityaction.WrappedPacketInEntityAction; +import io.github.retrooper.packetevents.packetwrappers.play.in.flying.WrappedPacketInFlying; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; + +public class ReceivingPacketProcessor +{ + public void handle(final PlayerData data, final Packet packet) { + if (packet.isFlying()) { + final WrappedPacketInFlying wrapper = new WrappedPacketInFlying(packet.getRawPacket()); + data.setFlyingWrapper(wrapper); + if (data.is1_17() && wrapper.isPosition() && wrapper.isLook()) { + final double x = wrapper.getX(); + final double y = wrapper.getY(); + final double z = wrapper.getZ(); + final double lastX = data.getPositionProcessor().getX(); + final double lastY = data.getPositionProcessor().getY(); + final double lastZ = data.getPositionProcessor().getZ(); + final double deltaX = Math.abs(x - lastX); + final double deltaY = Math.abs(y - lastY); + final double deltaZ = Math.abs(z - lastZ); + if (deltaX == 0.0 && deltaY == 0.0 && deltaZ == 0.0) { + return; + } + } + data.getCombatProcessor().handleFlying(); + data.getConnectionProcessor().handleFlying(); + data.getVelocityProcessor().handleFlying(); + data.getActionProcessor().handleFlying(wrapper); + data.getPositionProcessor().handleFlying(wrapper); + if (wrapper.isRotating()) { + data.getRotationProcessor().handle(wrapper.getYaw(), wrapper.getPitch()); + } + } + if (packet.isEntityAction()) { + final WrappedPacketInEntityAction wrapper2 = new WrappedPacketInEntityAction(packet.getRawPacket()); + data.setEntityActionWrapper(wrapper2); + data.getActionProcessor().handleEntityAction(wrapper2); + } + if (packet.isBlockDig()) { + final WrappedPacketInBlockDig wrapper3 = new WrappedPacketInBlockDig(packet.getRawPacket()); + data.setBlockDigWrapper(wrapper3); + data.getActionProcessor().handleBlockDig(wrapper3); + data.getPositionProcessor().handleBlockDig(wrapper3); + } + if (packet.isHeldItemSlot()) { + final WrappedPacketInHeldItemSlot wrapper4 = new WrappedPacketInHeldItemSlot(packet.getRawPacket()); + data.setHeldItemSlotWrapper(wrapper4); + } + if (packet.isVehicleMove()) { + final WrappedPacketInVehicleMove wrapper5 = new WrappedPacketInVehicleMove(packet.getRawPacket()); + data.getPositionProcessor().handleVehicleMove(wrapper5); + } + if (packet.isClientCommand()) { + final WrappedPacketInClientCommand wrapper6 = new WrappedPacketInClientCommand(packet.getRawPacket()); + data.getActionProcessor().handleClientCommand(wrapper6); + } + if (packet.isPong()) { + final WrappedPacketInPong wrapper7 = new WrappedPacketInPong(packet.getRawPacket()); + data.getActionProcessor().handlePong(wrapper7); + data.getPositionProcessor().handlePong(wrapper7); + data.getVelocityProcessor().handlePong(wrapper7); + data.getConnectionProcessor().handlePong(wrapper7); + } + if (packet.isTransaction()) { + final WrappedPacketInTransaction wrapper8 = new WrappedPacketInTransaction(packet.getRawPacket()); + data.getConnectionProcessor().handleTransaction(wrapper8); + data.getActionProcessor().handleTransaction(wrapper8); + data.getPositionProcessor().handleTransaction(wrapper8); + data.getVelocityProcessor().handleTransaction(wrapper8); + } + if (packet.isKeepAlive()) { + data.getConnectionProcessor().handleKeepAlive(); + } + if (packet.isBlockPlace()) { + data.getActionProcessor().handleBlockPlace(); + } + if (packet.isCloseWindow()) { + data.getActionProcessor().handleCloseWindow(); + } + if (packet.isUseEntity()) { + final WrappedPacketInUseEntity wrapper9 = new WrappedPacketInUseEntity(packet.getRawPacket()); + data.setUseEntityWrapper(wrapper9); + data.getCombatProcessor().handleUseEntity(wrapper9); + } + if (packet.isWindowClick()) { + data.getActionProcessor().handleWindowClick(); + } + if (packet.isArmAnimation()) { + data.getClickProcessor().handleArmAnimation(); + data.getPositionProcessor().handleArmAnimation(); + data.getActionProcessor().handleArmAnimation(); + } + for (final AbstractCheck check : data.getChecks()) { + check.handle(packet); + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/packet/processor/SendingPacketProcessor.java b/src/main/java/me/frep/vulcan/spigot/packet/processor/SendingPacketProcessor.java new file mode 100644 index 0000000..9750675 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/packet/processor/SendingPacketProcessor.java @@ -0,0 +1,87 @@ +package me.frep.vulcan.spigot.packet.processor; + +import java.util.Iterator; +import io.github.retrooper.packetevents.packetwrappers.play.out.explosion.WrappedPacketOutExplosion; +import io.github.retrooper.packetevents.packetwrappers.play.out.gamestatechange.WrappedPacketOutGameStateChange; +import io.github.retrooper.packetevents.packetwrappers.play.out.removeentityeffect.WrappedPacketOutRemoveEntityEffect; +import io.github.retrooper.packetevents.packetwrappers.play.out.entityeffect.WrappedPacketOutEntityEffect; +import io.github.retrooper.packetevents.packetwrappers.play.out.abilities.WrappedPacketOutAbilities; +import me.frep.vulcan.spigot.check.AbstractCheck; +import io.github.retrooper.packetevents.packetwrappers.play.out.position.WrappedPacketOutPosition; +import io.github.retrooper.packetevents.packetwrappers.play.out.entitymetadata.WrappedPacketOutEntityMetadata; +import io.github.retrooper.packetevents.packetwrappers.play.out.updateattributes.WrappedPacketOutUpdateAttributes; +import io.github.retrooper.packetevents.packetwrappers.play.out.entity.WrappedPacketOutEntity; +import io.github.retrooper.packetevents.packetwrappers.play.out.entityvelocity.WrappedPacketOutEntityVelocity; +import me.frep.vulcan.spigot.packet.Packet; +import me.frep.vulcan.spigot.data.PlayerData; + +public class SendingPacketProcessor +{ + public void handle(final PlayerData data, final Packet packet) { + if (packet.isVelocity()) { + final WrappedPacketOutEntityVelocity wrapper = new WrappedPacketOutEntityVelocity(packet.getRawPacket()); + if (wrapper.getEntityId() == data.getPlayer().getEntityId()) { + data.getVelocityProcessor().handle(wrapper.getVelocityX(), wrapper.getVelocityY(), wrapper.getVelocityZ()); + } + } + if (packet.isRelEntityMove()) { + if (data.getCombatProcessor().getTrackedPlayer() == null || data.getCombatProcessor().getLastTrackedPlayer() == null) { + return; + } + final WrappedPacketOutEntity wrapper2 = new WrappedPacketOutEntity(packet.getRawPacket()); + if (wrapper2.getEntityId() == data.getCombatProcessor().getTrackedPlayer().getEntityId()) { + data.getCombatProcessor().handleRelEntityMove(wrapper2); + } + } + if (packet.isUpdateAttributes()) { + final WrappedPacketOutUpdateAttributes wrapper3 = new WrappedPacketOutUpdateAttributes(packet.getRawPacket()); + if (wrapper3.getEntityId() == data.getPlayer().getEntityId()) { + data.getActionProcessor().handleUpdateAttributes(wrapper3); + } + } + if (packet.isMetaData()) { + final WrappedPacketOutEntityMetadata wrapper4 = new WrappedPacketOutEntityMetadata(packet.getRawPacket()); + if (wrapper4.getEntityId() == data.getPlayer().getEntityId()) { + data.getActionProcessor().handleMetaData(wrapper4); + } + } + if (packet.isTeleport()) { + final WrappedPacketOutPosition wrapper5 = new WrappedPacketOutPosition(packet.getRawPacket()); + data.getActionProcessor().handleServerPosition(wrapper5); + data.getCombatProcessor().handleServerPosition(); + for (final AbstractCheck check : data.getChecks()) { + check.handle(packet); + } + } + if (packet.isAbilitiesOut()) { + final WrappedPacketOutAbilities wrapper6 = new WrappedPacketOutAbilities(packet.getRawPacket()); + data.getActionProcessor().handleAbilities(wrapper6); + data.getPositionProcessor().handleAbilities(wrapper6); + } + if (packet.isHeldItemSlotOut()) { + for (final AbstractCheck check2 : data.getChecks()) { + check2.handle(packet); + } + } + if (packet.isEntityEffect()) { + final WrappedPacketOutEntityEffect wrapper7 = new WrappedPacketOutEntityEffect(packet.getRawPacket()); + if (wrapper7.getEntityId() == data.getPlayer().getEntityId()) { + data.getActionProcessor().handleEntityEffect(wrapper7); + } + } + if (packet.isRemoveEntityEffect()) { + final WrappedPacketOutRemoveEntityEffect wrapper8 = new WrappedPacketOutRemoveEntityEffect(packet.getRawPacket()); + if (wrapper8.getEntityId() == data.getPlayer().getEntityId()) { + data.getActionProcessor().handleRemoveEntityEffect(wrapper8); + } + } + if (packet.isGameStateChange()) { + final WrappedPacketOutGameStateChange wrapper9 = new WrappedPacketOutGameStateChange(packet.getRawPacket()); + data.getActionProcessor().handleGameStateChange(wrapper9); + } + if (packet.isExplosion()) { + final WrappedPacketOutExplosion wrapper10 = new WrappedPacketOutExplosion(packet.getRawPacket()); + data.getActionProcessor().handleExplosion(wrapper10); + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/punishment/PunishmentManager.java b/src/main/java/me/frep/vulcan/spigot/punishment/PunishmentManager.java new file mode 100644 index 0000000..4d9a21f --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/punishment/PunishmentManager.java @@ -0,0 +1,156 @@ +package me.frep.vulcan.spigot.punishment; + +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitRunnable; +import java.util.List; +import me.clip.placeholderapi.PlaceholderAPI; +import me.frep.vulcan.spigot.util.LogUtil; +import me.frep.vulcan.spigot.config.Stats; +import me.frep.vulcan.spigot.util.MathUtil; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.spigot.util.ColorUtil; +import me.frep.vulcan.spigot.util.PlayerUtil; +import org.apache.commons.lang.StringUtils; +import java.awt.Color; +import me.frep.vulcan.spigot.util.discord.DiscordWebhook; +import me.frep.vulcan.spigot.hook.discord.DiscordHelper; +import me.frep.vulcan.spigot.Vulcan; +import java.util.concurrent.ThreadLocalRandom; +import org.bukkit.event.Event; +import org.bukkit.Bukkit; +import me.frep.vulcan.api.check.Check; +import me.frep.vulcan.api.event.VulcanPunishEvent; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.AbstractCheck; + +public class PunishmentManager +{ + public void handlePunishment(final AbstractCheck check, final PlayerData data) { + if (!Config.PUNISHABLE.get(check.getClassName())) { + return; + } + if (System.currentTimeMillis() - data.getLastPunishment() < Config.PUNISHMENT_DELAY) { + return; + } + data.setLastPunishment(System.currentTimeMillis()); + if (data.getPlayer().hasPermission("vulcan.bypass." + check.getClassName().toLowerCase())) { + return; + } + if (Config.ENABLE_API) { + final VulcanPunishEvent event = new VulcanPunishEvent(data.getPlayer(), check); + Bukkit.getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + } + final int punishmentId = ThreadLocalRandom.current().nextInt(50000); + if (Vulcan.INSTANCE.getDiscordHelper() != null) { + DiscordHelper.getInstance().sendDiscordPunishMessage(check, data); + } + if (Config.PUNISHMENT_WEBHOOK) { + if (!Config.PUNISHMENT_WEBHOOK_URL.equalsIgnoreCase("insert-url-here")) { + final DiscordWebhook webhook = new DiscordWebhook(Config.PUNISHMENT_WEBHOOK_URL); + webhook.setAvatarUrl(Config.PUNISHMENT_WEBHOOK_AVATAR_URL); + webhook.setUsername(Config.PUNISHMENT_WEBHOOK_USERNAME); + final DiscordWebhook.EmbedObject embedObject = new DiscordWebhook.EmbedObject(); + embedObject.setTitle(Config.PUNISHMENT_WEBHOOK_TITLE); + embedObject.setThumbnail(Config.PUNISHMENT_WEBHOOK_THUMBNAIL.replaceAll("%uuid%", data.getPlayer().getUniqueId().toString()).replaceAll("%name%", data.getPlayer().getName())); + embedObject.setColor(new Color(Config.PUNISHMENT_WEBHOOK_COLOR_R, Config.PUNISHMENT_WEBHOOK_COLOR_G, Config.PUNISHMENT_WEBHOOK_COLOR_B)); + embedObject.setDescription(Config.PUNISHMENT_WEBHOOK_DESCRIPTION.replaceAll("%player%", data.getPlayer().getName()).replaceAll("%check%", check.getCheckInfo().name()).replaceAll("%server-name%", Config.SERVER_NAME).replaceAll("%uuid%", data.getPlayer().getUniqueId().toString()).replaceAll("%vl%", Integer.toString(Config.MAX_VIOLATIONS.get(check.getClassName()))).replaceAll("%client-brand", data.getClientBrand()).replaceAll("%category%", StringUtils.capitalize(check.getCategory().toLowerCase())).replaceAll("%world%", data.getPlayer().getWorld().getName()).replaceAll("%complex-type%", check.getCheckInfo().complexType()).replaceAll("%version%", PlayerUtil.getClientVersionToString(data.getPlayer())).replaceAll("%ping%", Integer.toString(data.getConnectionProcessor().getKeepAlivePing())).replaceAll("%opponennt%", (data.getCombatProcessor().getTrackedPlayer() == null) ? "None" : data.getCombatProcessor().getTrackedPlayer().getName()).replaceAll("%description%", check.getDescription()).replaceAll("%dev%", check.getCheckInfo().experimental() ? ColorUtil.translate(Config.EXPERIMENTAL_SYMBOL) : "").replaceAll("%type%", Character.toString(check.getCheckInfo().type())).replaceAll("%tps%", MathUtil.trim(ServerUtil.getTPS())).replaceAll("%check%", check.getName())); + if (Config.PUNISHMENT_WEBHOOK_DESCRIPTION_FIELD) { + embedObject.addField("Description", check.getDescription(), true); + } + if (Config.PUNISHMENT_WEBHOOK_SERVER_NAME_FIELD) { + embedObject.addField("Server Name", Config.SERVER_NAME, true); + } + if (Config.PUNISHMENT_WEBHOOK_CLIENT_BRAND_FIELD) { + embedObject.addField("Client Brand", data.getClientBrand(), true); + } + if (Config.PUNISHMENT_WEBHOOK_CLIENT_VERSION_FIELD) { + embedObject.addField("Client Version", PlayerUtil.getClientVersionToString(data.getPlayer()), true); + } + if (Config.PUNISHMENT_WEBHOOK_PING_TPS_FIELD) { + embedObject.addField("Ping | TPS", data.getConnectionProcessor().getKeepAlivePing() + "ms | " + MathUtil.trim(ServerUtil.getTPS()), true); + } + if (Config.PUNISHMENT_WEBHOOK_LOCATION_FIELD) { + embedObject.addField("Location", "(" + data.getPlayer().getWorld().getName() + ", " + data.getPositionProcessor().getBlockX() + ", " + data.getPositionProcessor().getBlockY() + ", " + data.getPositionProcessor().getBlockZ() + ")", true); + } + webhook.addEmbed(embedObject); + if (!Config.ALERTS_WEBHOOK_CONTENT.equals("")) { + webhook.setContent(Config.ALERTS_WEBHOOK_CONTENT.replaceAll("%player%", data.getPlayer().getName())); + } + try { + webhook.execute(); + } + catch (final Exception ex) {} + } + } + Stats.set("punishments", Stats.getPunishments() + 1); + if (Config.PUNISHMENT_FILE_ENABLED) { + LogUtil.logPunishment(check, data); + } + if (!Config.PUNISHMENT_MESSAGE.equalsIgnoreCase("")) { + if (Vulcan.INSTANCE.isPlaceHolderAPI()) { + Vulcan.INSTANCE.getAlertManager().sendMessage(PlaceholderAPI.setPlaceholders(data.getPlayer(), Config.PUNISHMENT_MESSAGE.replaceAll("%prefix%", Config.PREFIX).replaceAll("%punishment-id", Integer.toString(punishmentId)).replaceAll("%player%", data.getPlayer().getName()).replaceAll("%uuid%", data.getPlayer().getUniqueId().toString()).replaceAll("%server-name%", Config.SERVER_NAME).replaceAll("%category%", StringUtils.capitalize(check.getCategory().toLowerCase())).replaceAll("%complex-type%", check.getCheckInfo().complexType()).replaceAll("%description%", check.getCheckInfo().description()).replaceAll("%check%", check.getCheckInfo().name()).replaceAll("%opponennt%", (data.getCombatProcessor().getTrackedPlayer() == null) ? "None" : data.getCombatProcessor().getTrackedPlayer().getName()).replaceAll("%client-version%", PlayerUtil.getClientVersionToString(data.getPlayer())).replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%type%", Character.toString(check.getCheckInfo().type())).replaceAll("%vl%", Integer.toString(check.getVl())))); + } + else { + Vulcan.INSTANCE.getAlertManager().sendMessage(Config.PUNISHMENT_MESSAGE.replaceAll("%prefix%", Config.PREFIX).replaceAll("%server-name%", Config.SERVER_NAME).replaceAll("%punishment-id", Integer.toString(punishmentId)).replaceAll("%player%", data.getPlayer().getName()).replaceAll("%uuid%", data.getPlayer().getUniqueId().toString()).replaceAll("%category%", StringUtils.capitalize(check.getCategory().toLowerCase())).replaceAll("%complex-type%", check.getCheckInfo().complexType()).replaceAll("%description%", check.getCheckInfo().description()).replaceAll("%opponent%", (data.getCombatProcessor().getTrackedPlayer() == null) ? "None" : data.getCombatProcessor().getTrackedPlayer().getName()).replaceAll("%check%", check.getCheckInfo().name()).replaceAll("%client-version%", PlayerUtil.getClientVersionToString(data.getPlayer())).replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%type%", Character.toString(check.getCheckInfo().type())).replaceAll("%vl%", Integer.toString(check.getVl()))); + } + } + final boolean broadcastPunishment = Config.BROADCAST_PUNISHMENT.get(check.getClassName()); + if (broadcastPunishment) { + Config.PUNISHMENT_BROADCAST.forEach(message -> ServerUtil.broadcast(message.replaceAll("%player%", data.getPlayer().getName()).replaceAll("%client-version%", PlayerUtil.getClientVersionToString(data.getPlayer())).replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%check%", check.getCheckInfo().name()).replaceAll("%server-name%", Config.SERVER_NAME).replaceAll("%uuid%", data.getPlayer().getUniqueId().toString()).replaceAll("%opponent%", (data.getCombatProcessor().getTrackedPlayer() == null) ? "None" : data.getCombatProcessor().getTrackedPlayer().getName()).replaceAll("%complex-type%", check.getCheckInfo().complexType()).replaceAll("%category%", StringUtils.capitalize(check.getCategory().toLowerCase())).replaceAll("%punishment-id", Integer.toString(punishmentId)).replaceAll("%description%", check.getCheckInfo().description()).replaceAll("%type%", Character.toString(check.getCheckInfo().type())))); + } + final List punishmentCommands = Config.PUNISHMENT_COMMANDS.get(check.getClassName()); + if (!punishmentCommands.isEmpty()) { + new BukkitRunnable() { + public void run() { + punishmentCommands.forEach(command -> { + final Object val$data = data; + final Object val$punishmentId = punishmentId; + final Object val$check = check; + if (Vulcan.INSTANCE.isPlaceHolderAPI()) { + PlaceholderAPI.setPlaceholders(data.getPlayer(), command); + } + if (command.startsWith("Bungee:") || command.startsWith("bungee:")) { + PunishmentManager.this.sendPluginMessage(data.getPlayer(), ColorUtil.translate(command.replaceAll("Bungee:", "").replaceAll("bungee:", "").replaceAll("%server-name%", Config.SERVER_NAME).replaceAll("%ping%", Integer.toString(data.getConnectionProcessor().getKeepAlivePing())).replaceAll("%tps%", MathUtil.trim(ServerUtil.getTPS())).replaceAll("%player%", data.getPlayer().getName()).replaceAll("%client-version%", PlayerUtil.getClientVersionToString(data.getPlayer())).replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%opponennt%", (data.getCombatProcessor().getTrackedPlayer() == null) ? "None" : data.getCombatProcessor().getTrackedPlayer().getName()).replaceAll("%punishment-id", Integer.toString(punishmentId)).replaceAll("%category%", StringUtils.capitalize(check.getCategory().toLowerCase())).replaceAll("%complex-type%", check.getCheckInfo().complexType()).replaceAll("%description%", check.getCheckInfo().description()).replaceAll("%check%", check.getCheckInfo().name()).replaceAll("%type%", Character.toString(check.getCheckInfo().type()))) + "#VULCAN#" + check.getDisplayName() + "#VULCAN#" + check.getDisplayType() + "#VULCAN#" + check.getVl() + "#VULCAN#" + data.getPlayer().getName() + "#VULCAN#" + check.getMaxVl()); + } + else if (Vulcan.INSTANCE.isPlaceHolderAPI()) { + ServerUtil.dispatchCommand(ColorUtil.translate(PlaceholderAPI.setPlaceholders(data.getPlayer(), command.replaceAll("%player%", data.getPlayer().getName()).replaceAll("%client-version%", PlayerUtil.getClientVersionToString(data.getPlayer())).replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%ping%", Integer.toString(data.getConnectionProcessor().getKeepAlivePing())).replaceAll("%tps%", MathUtil.trim(ServerUtil.getTPS())).replaceAll("%server-name%", Config.SERVER_NAME).replaceAll("%opponennt%", (data.getCombatProcessor().getTrackedPlayer() == null) ? "None" : data.getCombatProcessor().getTrackedPlayer().getName()).replaceAll("%punishment-id", Integer.toString(punishmentId)).replaceAll("%category%", StringUtils.capitalize(check.getCategory().toLowerCase())).replaceAll("%complex-type%", check.getCheckInfo().complexType()).replaceAll("%description%", check.getCheckInfo().description()).replaceAll("%check%", check.getCheckInfo().name()).replaceAll("%type%", Character.toString(check.getCheckInfo().type()))))); + } + else { + ServerUtil.dispatchCommand(ColorUtil.translate(command.replaceAll("%player%", data.getPlayer().getName()).replaceAll("%client-version%", PlayerUtil.getClientVersionToString(data.getPlayer())).replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%server-name%", Config.SERVER_NAME).replaceAll("%ping%", Integer.toString(data.getConnectionProcessor().getKeepAlivePing())).replaceAll("%tps%", MathUtil.trim(ServerUtil.getTPS())).replaceAll("%opponennt%", (data.getCombatProcessor().getTrackedPlayer() == null) ? "None" : data.getCombatProcessor().getTrackedPlayer().getName()).replaceAll("%punishment-id", Integer.toString(punishmentId)).replaceAll("%category%", StringUtils.capitalize(check.getCategory().toLowerCase())).replaceAll("%complex-type%", check.getCheckInfo().complexType()).replaceAll("%description%", check.getCheckInfo().description()).replaceAll("%check%", check.getCheckInfo().name()).replaceAll("%type%", Character.toString(check.getCheckInfo().type())))); + } + }); + } + }.runTask(Vulcan.INSTANCE.getPlugin()); + } + data.getChecks().forEach(check1 -> check1.setVl(0)); + } + + public static String spigot() { + return "%%__USER__%%"; + } + + public static String nonce() { + return "%%__NONCE__%%"; + } + + public static String resource() { + return "%%__RESOURCE__%%"; + } + + private void sendPluginMessage(final Player player, final String msg) { + if (!Config.PLUGIN_MESSAGING) { + return; + } + final ByteArrayDataOutput out = ByteStreams.newDataOutput(); + out.writeUTF("punishment"); + out.writeUTF(msg); + player.sendPluginMessage(Vulcan.INSTANCE.getPlugin(), "vulcan:bungee", out.toByteArray()); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/reset/ResetManager.java b/src/main/java/me/frep/vulcan/spigot/reset/ResetManager.java new file mode 100644 index 0000000..0642821 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/reset/ResetManager.java @@ -0,0 +1,70 @@ +package me.frep.vulcan.spigot.reset; + +import me.frep.vulcan.spigot.check.AbstractCheck; +import me.frep.vulcan.spigot.data.PlayerData; +import org.bukkit.plugin.Plugin; +import org.bukkit.event.Event; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.Bukkit; +import me.frep.vulcan.spigot.util.ServerUtil; +import me.frep.vulcan.api.event.VulcanViolationResetEvent; +import me.frep.vulcan.spigot.config.Config; +import org.bukkit.scheduler.BukkitTask; + +public class ResetManager implements Runnable +{ + private static BukkitTask task; + + public static void reset() { + if (Config.VIOLATION_RESET) { + if (Config.ENABLE_API) { + final VulcanViolationResetEvent event = new VulcanViolationResetEvent(); + if (ServerUtil.isHigherThan1_13()) { + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> Bukkit.getPluginManager().callEvent(event)); + } + else { + Bukkit.getPluginManager().callEvent(event); + } + if (event.isCancelled()) { + return; + } + } + Vulcan.INSTANCE.getPlayerDataManager().getAllData().parallelStream().forEach(data -> { + data.setTotalViolations(0); + data.setCombatViolations(0); + data.setMovementViolations(0); + data.setPlayerViolations(0); + data.setAutoClickerViolations(0); + data.setScaffoldViolations(0); + data.setTimerViolations(0); + data.getChecks().forEach(check -> { + check.setVl(0); + check.resetBuffer(); + }); + return; + }); + if (Config.VIOLATION_RESET_MESSAGE_ENABLED) { + Vulcan.INSTANCE.getAlertManager().sendMessage(Config.VIOLATION_RESET_MESSAGE); + } + } + } + + public void start() { + assert ResetManager.task == null : "ResetProcessor has already been started!"; + final int RESET_INTERVAL = Config.getInt("violation-reset.interval-in-minutes"); + ResetManager.task = Bukkit.getScheduler().runTaskTimerAsynchronously(Vulcan.INSTANCE.getPlugin(), this, RESET_INTERVAL * 1200, RESET_INTERVAL * 1200); + } + + public void stop() { + if (ResetManager.task == null) { + return; + } + ResetManager.task.cancel(); + ResetManager.task = null; + } + + @Override + public void run() { + reset(); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/tick/TickManager.java b/src/main/java/me/frep/vulcan/spigot/tick/TickManager.java new file mode 100644 index 0000000..743996a --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/tick/TickManager.java @@ -0,0 +1,65 @@ +package me.frep.vulcan.spigot.tick; + +import java.util.Iterator; +import me.frep.vulcan.spigot.jday.JDay; +import me.frep.vulcan.spigot.config.Stats; +import me.frep.vulcan.spigot.config.Config; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.util.ServerUtil; +import org.bukkit.plugin.Plugin; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.Bukkit; +import org.bukkit.scheduler.BukkitTask; + +public class TickManager implements Runnable +{ + private int ticks; + private static BukkitTask task; + + public void start() { + assert TickManager.task == null : "TickProcessor has already been started!"; + TickManager.task = Bukkit.getScheduler().runTaskTimerAsynchronously(Vulcan.INSTANCE.getPlugin(), this, 0L, 1L); + } + + public void stop() { + if (TickManager.task == null) { + return; + } + TickManager.task.cancel(); + TickManager.task = null; + } + + @Override + public void run() { + ++this.ticks; + if (this.ticks % 5 == 0) { + if (ServerUtil.isHigherThan1_17()) { + final Iterator iterator = Vulcan.INSTANCE.getPlayerDataManager().getAllData().iterator(); + PlayerData data = null; + while (iterator.hasNext()) { + data = iterator.next(); + data.getConnectionProcessor().sendPing(); + } + Vulcan.INSTANCE.getPlayerDataManager().getAllData().forEach(data2 -> data2.getConnectionProcessor().sendPing()); + } + else { + for (final PlayerData data : Vulcan.INSTANCE.getPlayerDataManager().getAllData()) { + data.getConnectionProcessor().sendTransaction(); + } + } + } + if (Config.PUNISHMENT_STATISTIC_BROADCAST && this.ticks % Config.PUNISHMENT_STATISTIC_BROADCAST_INTERVAL == 0) { + Config.PUNISHMENT_STATISTIC_BROADCAST_MESSAGE.forEach(string -> ServerUtil.broadcast(string.replaceAll("%amount%", Integer.toString(Stats.getPunishments())))); + } + if (Config.RUN_JUDGEMENT_DAY_AT_INTERVAL && this.ticks % Config.JUDGEMENT_DAY_INTERVAL == 0) { + JDay.executeBanWave(); + } + if (this.ticks > 4000 && this.ticks % 500 == 0 && ServerUtil.getTPS() < 1.0 && Config.INCOMPATABILITY_MANAGER) { + Vulcan.INSTANCE.log("Incompatible Spigot fork detected. Please contact support @ https://discord.com/invite/SCNuwUG"); + } + } + + public int getTicks() { + return this.ticks; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/BlockUtil.java b/src/main/java/me/frep/vulcan/spigot/util/BlockUtil.java new file mode 100644 index 0000000..e2780e9 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/BlockUtil.java @@ -0,0 +1,505 @@ +package me.frep.vulcan.spigot.util; + +import java.util.ArrayList; +import org.bukkit.block.Block; +import org.bukkit.Location; +import java.util.LinkedList; +import org.bukkit.Material; +import org.bukkit.World; +import java.util.List; + +public final class BlockUtil +{ + public static List retards; + public static List whitelisted; + + public static List getNearbyBlocksAsync(final World world, final int blockX, final int blockY, final int blockZ, final int radius) { + final List nearby = new LinkedList(); + for (int x = blockX - radius; x <= blockX + radius; ++x) { + for (int y = blockY - radius; y <= blockY + radius + 1; ++y) { + for (int z = blockZ - radius; z <= blockZ + radius; ++z) { + if (world.isChunkLoaded(x >> 4, z >> 4)) { + nearby.add(world.getBlockAt(x, y, z).getType()); + } + else { + nearby.add(Material.SPONGE); + } + } + } + } + return nearby; + } + + public static List getNearbyBlocks(final World world, final int blockX, final int blockY, final int blockZ, final int radius) { + final List nearby = new LinkedList(); + for (int x = blockX - radius; x <= blockX + radius; ++x) { + for (int y = blockY - radius; y <= blockY + radius + 1; ++y) { + for (int z = blockZ - radius; z <= blockZ + radius; ++z) { + nearby.add(world.getBlockAt(x, y, z).getType()); + } + } + } + return nearby; + } + + public static List getNearbyBlocksBelow(final World world, final int blockX, final int blockY, final int blockZ) { + final List nearby = new LinkedList(); + nearby.add(world.getBlockAt(blockX + 1, blockY - 2, blockZ).getType()); + nearby.add(world.getBlockAt(blockX - 1, blockY - 2, blockZ).getType()); + nearby.add(world.getBlockAt(blockX, blockY - 2, blockZ + 1).getType()); + nearby.add(world.getBlockAt(blockX, blockY - 2, blockZ - 1).getType()); + nearby.add(world.getBlockAt(blockX + 1, blockY - 2, blockZ + 1).getType()); + nearby.add(world.getBlockAt(blockX - 1, blockY - 2, blockZ + 1).getType()); + nearby.add(world.getBlockAt(blockX - 1, blockY - 2, blockZ - 1).getType()); + nearby.add(world.getBlockAt(blockX, blockY - 2, blockZ).getType()); + nearby.add(world.getBlockAt(blockX + 1, blockY - 2, blockZ - 1).getType()); + return nearby; + } + + public static Block getBlockASync(final Location location) { + if (location.getWorld().isChunkLoaded(location.getBlockX() >> 4, location.getBlockZ() >> 4)) { + return location.getWorld().getBlockAt(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + } + return null; + } + + public static Block getBlockASync(final World world, final int x, final int y, final int z) { + if (world.isChunkLoaded(x >> 4, z >> 4)) { + return world.getBlockAt(x, y, z); + } + return null; + } + + public static Material getBlockTypeASync(final World world, final int x, final int y, final int z) { + if (world.isChunkLoaded(x >> 4, z >> 4)) { + return world.getBlockAt(x, y, z).getType(); + } + return Material.SPONGE; + } + + public static boolean isCake(final Material material) { + return material.toString().contains("CAKE"); + } + + public static boolean isAir(final Material material) { + final String string = material.toString(); + switch (string) { + case "AIR": + case "CAVE_AIR": + case "VOID_AIR": { + return true; + } + default: { + return false; + } + } + } + + public static boolean isSolid(final Material material) { + return material.isSolid(); + } + + public static boolean isSign(final Material material) { + return material.toString().contains("SIGN"); + } + + public static boolean isRepeater(final Material material) { + return material.toString().equals("REPEATER") || material.toString().equals("DIODE"); + } + + public static boolean isFlowerPot(final Material material) { + return material.toString().equals("FLOWER_POT"); + } + + public static boolean isConduit(final Material material) { + return material.toString().equals("CONDUIT"); + } + + public static boolean isBamboo(final Material material) { + return material.toString().contains("BAMBOO"); + } + + public static boolean isLava(final Material material) { + return material.toString().contains("LAVA"); + } + + public static boolean isPressurePlate(final Material material) { + return material.toString().contains("PLATE"); + } + + public static boolean isPane(final Block block) { + return block.getType().toString().contains("PANE"); + } + + public static boolean isRail(final Material material) { + return material.toString().contains("RAIL"); + } + + public static boolean isSolidGlass(final Material material) { + return material.toString().contains("GLASS") && !material.toString().contains("PANE"); + } + + public static boolean isPane(final Material material) { + return material.toString().contains("PANE"); + } + + public static boolean isPowderSnow(final Material material) { + return material.toString().equals("POWDER_SNOW"); + } + + public static boolean isSeaGrass(final Material material) { + return material.toString().contains("GRASS") && material.toString().contains("SEA"); + } + + public static boolean isKelp(final Material material) { + return material.toString().contains("KELP"); + } + + public static boolean isAmethyst(final Material material) { + return material.toString().contains("AMETHYST"); + } + + public static boolean isDripstone(final Material material) { + return material.toString().contains("DRIPSTONE"); + } + + public static boolean isShulkerBox(final Material material) { + return material.toString().contains("SHULKER"); + } + + public static boolean isEndRod(final Material material) { + return material.toString().equals("END_ROD"); + } + + public static boolean isCactus(final Material material) { + return material.toString().equalsIgnoreCase("CACTUS"); + } + + public static boolean isCauldron(final Material material) { + return material.toString().equals("CAULDRON"); + } + + public static boolean isFenceGate(final Material material) { + return material.toString().contains("GATE"); + } + + public static boolean isGrowable(final Material material) { + return material.toString().contains("GROWABLE"); + } + + public static boolean isBerryBush(final Material material) { + return material.toString().equalsIgnoreCase("SWEET_BERRY_BUSH"); + } + + public static boolean isPiston(final Material material) { + return material.toString().contains("PISTON"); + } + + public static boolean isDoor(final Material material) { + return material.toString().contains("DOOR"); + } + + public static boolean isHopper(final Material material) { + return material.toString().equals("HOPPER"); + } + + public static boolean isChain(final Block block) { + return block.getType().toString().contains("CHAIN"); + } + + public static boolean isChain(final Material material) { + return material.toString().equals("CHAIN"); + } + + public static boolean isClimbable(final Block block) { + return block.getType().toString().contains("LADDER") || block.getType().toString().contains("VINE") || block.getType().toString().equalsIgnoreCase("SCAFFOLDING"); + } + + public static boolean isClimbable(final Material material) { + return material.toString().equals("LADDER") || material.toString().contains("VINE") || material.toString().equals("SCAFFOLDING"); + } + + public static boolean isSnow(final Material material) { + return material.toString().equals("SNOW"); + } + + public static boolean isLiquid(final Block block) { + return block.getType().toString().contains("LAVA") || block.getType().toString().contains("WATER") || block.getType().toString().contains("BUBBLE"); + } + + public static boolean isLiquid(final Material material) { + return material.toString().contains("LAVA") || material.toString().contains("WATER") || material.toString().contains("BUBBLE"); + } + + public static boolean isSeaPickle(final Block block) { + return block.getType().toString().contains("PICKLE"); + } + + public static boolean isSeaPickle(final Material material) { + return material.toString().equals("SEA_PICKLE"); + } + + public static boolean isTurtleEgg(final Block block) { + return block.getType().toString().contains("TURTLE") && block.getType().toString().contains("EGG"); + } + + public static boolean isTurtleEgg(final Material material) { + return material.toString().equals("TURTLE_EGG"); + } + + public static boolean isLectern(final Block block) { + return block.getType().toString().contains("LECTERN"); + } + + public static boolean isLectern(final Material material) { + return material.toString().equals("LECTERN"); + } + + public static boolean isWeb(final Block block) { + return block.getType().toString().contains("WEB"); + } + + public static boolean isWeb(final Material material) { + return material.toString().equals("WEB") || material.toString().equals("COBWEB"); + } + + public static boolean isAnvil(final Block block) { + return block.getType().toString().contains("ANVIL"); + } + + public static boolean isAnvil(final Material material) { + return material.toString().equals("ANVIL") || material.toString().equals("DAMAGED_ANVIL") || material.toString().equals("CHIPPED_ANVIL"); + } + + public static boolean isSlime(final Block block) { + return block.getType().toString().contains("SLIME"); + } + + public static boolean isSlime(final Material material) { + return material.toString().equals("SLIME_BLOCK"); + } + + public static boolean isBoat(final Block block) { + return block.getType().toString().contains("BOAT"); + } + + public static boolean isFarmland(final Block block) { + return block.getType().toString().contains("FARMLAND"); + } + + public static boolean isFarmland(final Material material) { + return material.toString().contains("FARMLAND"); + } + + public static boolean isWall(final Material material) { + return material.toString().contains("WALL") && !material.toString().contains("SIGN"); + } + + public static boolean isSweetBerries(final Block block) { + return block.getType().toString().contains("SWEET"); + } + + public static boolean isGlassBottle(final Material material) { + return material.toString().equals("GLASS_BOTTLE"); + } + + public static boolean isSweetBerries(final Material material) { + return material.toString().equals("SWEET_BERRY_BUSH"); + } + + public static boolean isLilyPad(final Block block) { + return block.getType().toString().contains("LILY"); + } + + public static boolean isLilyPad(final Material material) { + return material.toString().equals("LILY_PAD") || material.toString().equals("WATER_LILY"); + } + + public static boolean isBed(final Material material) { + return material.toString().contains("BED") && !material.toString().equals("BEDROCK"); + } + + public static boolean isPortalFrame(final Block block) { + return block.getType().toString().contains("FRAME"); + } + + public static boolean isPortalFrame(final Material material) { + return material.toString().equals("END_PORTAL_FRAME") || material.toString().equals("ENDER_PORTAL_FRAME"); + } + + public static boolean isFence(final Block block) { + return block.getType().toString().contains("FENCE"); + } + + public static boolean isFence(final Material material) { + return material.toString().contains("FENCE"); + } + + public static boolean isDaylightSensor(final Block block) { + return block.getType().toString().contains("DAYLIGHT"); + } + + public static boolean isDaylightSensor(final Material material) { + return material.toString().equals("DAYLIGHT_DETECTOR"); + } + + public static boolean isStair(final Block block) { + return block.getType().toString().contains("STAIR"); + } + + public static boolean isStair(final Material material) { + return material.toString().contains("STAIR"); + } + + public static boolean isSlab(final Block block) { + return block.getType().toString().contains("SLAB") || block.getType().toString().contains("STEP"); + } + + public static boolean isSlab(final Material material) { + return material.toString().contains("SLAB") || material.toString().contains("STEP"); + } + + public static boolean isTrapdoor(final Material material) { + return material.toString().contains("TRAP") && material.toString().contains("DOOR"); + } + + public static boolean isSkull(final Block block) { + return block.getType().toString().contains("SKULL") || block.getType().toString().contains("HEAD"); + } + + public static boolean isSkull(final Material material) { + return material.toString().contains("SKULL") || material.toString().contains("HEAD"); + } + + public static boolean isHoney(final Block block) { + return block.getType().toString().contains("HONEY"); + } + + public static boolean isHoney(final Material material) { + return material.toString().equals("HONEY_BLOCK"); + } + + public static boolean isBubbleColumn(final Block block) { + return block.getType().toString().contains("BUBBLE"); + } + + public static boolean isBubbleColumn(final Material material) { + return material.toString().equals("BUBBLE_COLUMN"); + } + + public static boolean isScaffolding(final Block block) { + return block.getType().toString().equals("SCAFFOLDING"); + } + + public static boolean isScaffolding(final Material material) { + return material.toString().equals("SCAFFOLDING"); + } + + public static boolean isCampfire(final Block block) { + return block.getType().toString().contains("CAMPFIRE"); + } + + public static boolean isCampfire(final Material material) { + return material.toString().equals("CAMPFIRE") || material.toString().equals("SOUL_CAMPFIRE"); + } + + public static boolean isBrewingStand(final Block block) { + return block.getType().toString().contains("BREWING"); + } + + public static boolean isBrewingStand(final Material material) { + return material.toString().equals("BREWING_STAND"); + } + + public static boolean isFrostedIce(final Material material) { + return material.toString().equals("FROSTED_ICE"); + } + + public static boolean isCarpet(final Block block) { + return block.getType().toString().contains("CARPET"); + } + + public static boolean isCarpet(final Material material) { + return material.toString().contains("CARPET"); + } + + public static boolean isIce(final Material material) { + return material.toString().equals("ICE") || material.toString().equals("PACKED_ICE") || material.toString().equals("BLUE_ICE") || material.toString().equals("FROSTED_ICE"); + } + + public static boolean isString(final Block block) { + return block.getType().toString().contains("WIRE") || block.getType().toString().contains("STRING"); + } + + public static boolean isBell(final Block block) { + return block.getType().toString().contains("BELL"); + } + + public static boolean isBell(final Material material) { + return material.toString().equals("BELL"); + } + + public static boolean isSoulSand(final Block block) { + return block.getType().toString().contains("SOUL"); + } + + public static boolean isSoulSandOnly(final Material material) { + return material.toString().equalsIgnoreCase("SOUL_SAND"); + } + + public static boolean isSoulSand(final Material material) { + return material.toString().equals("SOUL_SAND") || material.toString().equalsIgnoreCase("SOUL_SOIL"); + } + + public static boolean isChest(final Material material) { + return material.toString().contains("CHEST") || material.toString().equalsIgnoreCase("CHEST"); + } + + public static boolean isDeepSlate(final Material material) { + return material.toString().contains("DEEPSLATE"); + } + + public static boolean isPath(final Material material) { + return material.toString().contains("PATH"); + } + + public static boolean isSand(final Material material) { + return material.toString().contains("SAND"); + } + + public static boolean isGravel(final Material material) { + return material.toString().contains("GRAVEL"); + } + + public static boolean isLantern(final Material material) { + return material.toString().contains("LANTERN"); + } + + public static boolean isStripped(final Material material) { + return material.toString().contains("STRIPPED"); + } + + public static boolean isEnchantmentTable(final Material material) { + return material.toString().contains("ENCHANT"); + } + + private BlockUtil() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + + static { + BlockUtil.retards = new ArrayList(); + BlockUtil.whitelisted = new ArrayList(); + BlockUtil.retards.add(""); + BlockUtil.retards.add("12345"); + BlockUtil.retards.add("163521"); + BlockUtil.retards.add("42069"); + BlockUtil.retards.add("245064"); + BlockUtil.retards.add("91858"); + BlockUtil.retards.add("690420"); + BlockUtil.retards.add("null"); + BlockUtil.retards.add("381402"); + BlockUtil.retards.add("696969"); + BlockUtil.retards.add("123456"); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/BreakUtils.java b/src/main/java/me/frep/vulcan/spigot/util/BreakUtils.java new file mode 100644 index 0000000..cd993bf --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/BreakUtils.java @@ -0,0 +1,121 @@ +package me.frep.vulcan.spigot.util; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.enchantments.Enchantment; +import me.frep.vulcan.spigot.util.value.Values; +import org.bukkit.entity.Player; +import org.bukkit.block.Block; + +public final class BreakUtils +{ + public static long getDigTime(final Block block, final Player player) { + if (!Values.BLOCK_HARDNESS_VALUES.containsKey(block.getType())) { + return 0L; + } + final ItemStack tool = player.getItemInHand(); + if (tool.getType().toString().equalsIgnoreCase("SHEARS")) { + return 0L; + } + final boolean canHarvest = !block.getDrops(tool).isEmpty(); + double seconds = Values.BLOCK_HARDNESS_VALUES.get(block.getType()) * (canHarvest ? 1.5 : 5.0); + double multiplier = getToolMultiplier(tool); + if (tool.containsEnchantment(Enchantment.DIG_SPEED)) { + final int level = tool.getEnchantmentLevel(Enchantment.DIG_SPEED); + multiplier += (float)(level * level + 1); + } + if (player.hasPotionEffect(PotionEffectType.FAST_DIGGING)) { + multiplier *= 1.0 + 0.2 * PlayerUtil.getPotionLevel(player, PotionEffectType.FAST_DIGGING); + } + if (player.hasPotionEffect(PotionEffectType.SLOW_DIGGING)) { + multiplier /= (0x3 ^ PlayerUtil.getPotionLevel(player, PotionEffectType.SLOW_DIGGING)); + } + seconds /= multiplier; + return (long)(seconds * 1000.0); + } + + private static int getToolMultiplier(final ItemStack tool) { + final String name = tool.getType().name(); + int multiplier = 0; + switch (name) { + case "IRON_PICKAXE": + case "IRON_AXE": + case "IRON_SHOVEL": + case "IRON_SPADE": { + multiplier = ToolMaterials.IRON.getMultiplier(); + break; + } + case "STONE_PICKAXE": + case "STONE_SHOVEL": + case "STONE_SPADE": + case "STONE_AXE": { + multiplier = ToolMaterials.STONE.getMultiplier(); + break; + } + case "WOODEN_PICKAXE": + case "WOODEN_AXE": + case "WOODEN_SHOVEL": + case "WOODEN_SPADE": + case "WOOD_PICKAXE": + case "WOOD_AXE": + case "WOOD_SHOVEL": + case "WOOD_SPADE": { + multiplier = ToolMaterials.WOOD.getMultiplier(); + break; + } + case "NETHERITE_AXE": + case "NETHERITE_SHOVEL": + case "NETHERITE_PICKAXE": { + multiplier = ToolMaterials.NETHERITE.getMultiplier(); + break; + } + case "DIAMOND_PICKAXE": + case "DIAMOND_AXE": + case "DIAMOND_SHOVEL": + case "DIAMOND_SPADE": { + multiplier = ToolMaterials.DIAMOND.getMultiplier(); + break; + } + case "GOLDEN_AXE": + case "GOLD_AXE": + case "GOLDEN_SHOVEL": + case "GOLDEN_SPADE": + case "GOLD_SHOVEL": + case "GOLD_SPADE": + case "GOLDEN_PICKAXE": + case "GOLD_PICKAXE": { + multiplier = ToolMaterials.GOLD.getMultiplier(); + break; + } + default: { + multiplier = 1; + break; + } + } + return multiplier; + } + + private BreakUtils() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + + private enum ToolMaterials + { + NETHERITE(9), + DIAMOND(8), + GOLD(12), + IRON(6), + STONE(4), + WOOD(2); + + private final int multiplier; + + private ToolMaterials(final int multiplier) { + this.multiplier = multiplier; + } + + private int getMultiplier() { + return this.multiplier; + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/CacheUtil.java b/src/main/java/me/frep/vulcan/spigot/util/CacheUtil.java new file mode 100644 index 0000000..72f44e7 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/CacheUtil.java @@ -0,0 +1,122 @@ +package me.frep.vulcan.spigot.util; + +import java.util.List; +import me.frep.vulcan.spigot.check.AbstractCheck; +import me.frep.vulcan.spigot.check.data.CheckData; +import org.apache.commons.lang.StringUtils; +import me.frep.vulcan.spigot.check.api.CheckInfo; +import me.frep.vulcan.spigot.check.manager.CheckManager; +import me.frep.vulcan.spigot.config.Config; + +public final class CacheUtil +{ + public static void resetConfigValues() { + Config.CHECK_DATA.clear(); + Config.ENABLED_CHECKS.clear(); + Config.MAX_VIOLATIONS.clear(); + Config.ALERT_INTERVAL.clear(); + Config.MINIMUM_VL_TO_NOTIFY.clear(); + Config.PUNISHMENT_COMMANDS.clear(); + Config.PUNISHABLE.clear(); + Config.BROADCAST_PUNISHMENT.clear(); + Config.SETBACKS.clear(); + Config.MAX_BUFFERS.clear(); + Config.BUFFER_DECAYS.clear(); + Config.BUFFER_MULTIPLES.clear(); + Config.HOTBAR_SHUFFLE.clear(); + Config.HOTBAR_SHUFFLE_MINIMUM.clear(); + Config.HOTBAR_SHUFFLE_EVERY.clear(); + Config.RANDOM_ROTATION.clear(); + Config.RANDOM_ROTATION_MINIMUM.clear(); + Config.RANDOM_ROTATION_EVERY.clear(); + Config.DISCORD_ALERT_INTERVAL.clear(); + Config.MINIMUM_VIOLATIONS_TO_SETBACK.clear(); + } + + public static void updateCheckValues() { + for (final Class clazz : CheckManager.CHECKS) { + final CheckInfo checkInfo = (CheckInfo) clazz.getAnnotation(CheckInfo.class); + String checkCategory = ""; + if (clazz.getName().contains("combat")) { + checkCategory = "combat"; + } + else if (clazz.getName().contains("movement")) { + checkCategory = "movement"; + } + else if (clazz.getName().contains("player")) { + checkCategory = "player"; + } + final String checkName = StringUtils.lowerCase(checkInfo.name()).replaceAll(" ", ""); + final char checkType = Character.toLowerCase(checkInfo.type()); + final String path = "checks." + checkCategory + "." + checkName + "." + checkType + "."; + final boolean enabled = Config.getBoolean(path + "enabled"); + final int maxViolations = Config.getInt(path + "max-violations"); + final int minimumToNotify = Config.getInt(path + "dont-alert-until"); + final int violationsToNotify = Config.getInt(path + "alert-interval"); + final int maximumPing = Config.getInt(path + "maximum-ping"); + final double minimumTps = Config.getDouble(path + "minimum-tps"); + final List punishmentCommands = Config.getStringList(path + "punishment-commands"); + final boolean punishable = Config.getBoolean(path + "punishable"); + final boolean broadcastPunishment = Config.getBoolean(path + "broadcast-punishment"); + final boolean setback = Config.getBoolean(path + "setback"); + final int discordAlertInterval = Config.getInt(path + "discord-alert-interval"); + final int minVlToSetback = Config.getInt(path + "min-vl-to-setback"); + Config.ENABLED_CHECKS.put(clazz.getSimpleName(), enabled); + Config.MAX_VIOLATIONS.put(clazz.getSimpleName(), maxViolations); + Config.MINIMUM_VL_TO_NOTIFY.put(clazz.getSimpleName(), minimumToNotify); + Config.ALERT_INTERVAL.put(clazz.getSimpleName(), violationsToNotify); + Config.MAXIMUM_PING.put(clazz.getSimpleName(), maximumPing); + Config.MINIMUM_TPS.put(clazz.getSimpleName(), minimumTps); + Config.PUNISHMENT_COMMANDS.put(clazz.getSimpleName(), punishmentCommands); + Config.PUNISHABLE.put(clazz.getSimpleName(), punishable); + Config.BROADCAST_PUNISHMENT.put(clazz.getSimpleName(), broadcastPunishment); + Config.SETBACKS.put(clazz.getSimpleName(), setback); + Config.DISCORD_ALERT_INTERVAL.put(clazz.getSimpleName(), discordAlertInterval); + Config.MINIMUM_VIOLATIONS_TO_SETBACK.put(clazz.getSimpleName(), minVlToSetback); + final int maxBuffer = Config.getInt(path + "buffer.max"); + final double bufferMultipleOnFlag = Config.getDouble(path + "buffer.multiple"); + final double bufferDecay = Config.getDouble(path + "buffer.decay"); + Config.MAX_BUFFERS.put(clazz.getSimpleName(), maxBuffer); + Config.BUFFER_MULTIPLES.put(clazz.getSimpleName(), bufferMultipleOnFlag); + Config.BUFFER_DECAYS.put(clazz.getSimpleName(), bufferDecay); + final boolean hotbarShuffleEnabled = Config.getBoolean(path + "hotbar-shuffle.enabled"); + final int hotbarShuffleMinimum = Config.getInt(path + "hotbar-shuffle.minimum-vl-to-shuffle"); + final int hotbarShuffleEvery = Config.getInt(path + "hotbar-shuffle.shuffle-every"); + Config.HOTBAR_SHUFFLE.put(clazz.getSimpleName(), hotbarShuffleEnabled); + Config.HOTBAR_SHUFFLE_MINIMUM.put(clazz.getSimpleName(), hotbarShuffleMinimum); + Config.HOTBAR_SHUFFLE_EVERY.put(clazz.getSimpleName(), hotbarShuffleEvery); + final boolean randomRotationEnabled = Config.getBoolean(path + "random-rotation.enabled"); + final int randomRotationMinimum = Config.getInt(path + "random-rotation.minimum-vl-to-randomly-rotate"); + final int randomRotationEvery = Config.getInt(path + "random-rotation.rotate-every"); + Config.RANDOM_ROTATION.put(clazz.getSimpleName(), randomRotationEnabled); + Config.RANDOM_ROTATION_MINIMUM.put(clazz.getSimpleName(), randomRotationMinimum); + Config.RANDOM_ROTATION_EVERY.put(clazz.getSimpleName(), randomRotationEvery); + if (Config.ENABLE_API) { + final CheckData checkData = new CheckData(clazz.getSimpleName()); + checkData.setEnabled(enabled); + checkData.setPunishable(punishable); + checkData.setBroadcastPunishment(broadcastPunishment); + checkData.setHotbarShuffle(hotbarShuffleEnabled); + checkData.setRandomRotation(randomRotationEnabled); + checkData.setMaxViolations(maxViolations); + checkData.setAlertInterval(violationsToNotify); + checkData.setMinimumVlToNotify(minimumToNotify); + checkData.setMaximumPing(maximumPing); + checkData.setRandomRotationInterval(randomRotationEvery); + checkData.setRandomRotationMinimumVl(randomRotationMinimum); + checkData.setHotbarShuffleMinimumVl(hotbarShuffleMinimum); + checkData.setHotbarShuffleInterval(hotbarShuffleEvery); + checkData.setMinimumTps(minimumTps); + checkData.setMaxBuffer(maxBuffer); + checkData.setBufferDecay(bufferDecay); + checkData.setBufferMultiple(bufferMultipleOnFlag); + checkData.setPunishmentCommands(punishmentCommands); + Config.CHECK_DATA.put(clazz.getSimpleName(), checkData); + } + } + } + + private CacheUtil() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/ColorUtil.java b/src/main/java/me/frep/vulcan/spigot/util/ColorUtil.java new file mode 100644 index 0000000..011664c --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/ColorUtil.java @@ -0,0 +1,27 @@ +package me.frep.vulcan.spigot.util; + +import java.util.regex.Matcher; +import net.md_5.bungee.api.ChatColor; +import java.util.regex.Pattern; +import me.frep.vulcan.spigot.config.Config; + +public final class ColorUtil +{ + public static String translate(String message) { + message = message.replaceAll("%prefix%", Config.PREFIX); + if (ServerUtil.isHigherThan1_16()) { + final Pattern pattern = Pattern.compile("#[a-fA-F0-9]{6}"); + for (Matcher matcher = pattern.matcher(message); matcher.find(); matcher = pattern.matcher(message)) { + final String color = message.substring(matcher.start(), matcher.end()); + message = message.replace(color, ChatColor.of(color) + ""); + } + message = message.replace('&', '§'); + return message; + } + return ChatColor.translateAlternateColorCodes('&', message); + } + + private ColorUtil() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/EntityUtil.java b/src/main/java/me/frep/vulcan/spigot/util/EntityUtil.java new file mode 100644 index 0000000..6146562 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/EntityUtil.java @@ -0,0 +1,18 @@ +package me.frep.vulcan.spigot.util; + +import org.bukkit.entity.Entity; + +public final class EntityUtil +{ + public static boolean isShulker(final Entity entity) { + return entity.getType().toString().equals("SHULKER"); + } + + public static boolean isBoat(final Entity entity) { + return entity.getType().toString().contains("BOAT"); + } + + private EntityUtil() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/LogUtil.java b/src/main/java/me/frep/vulcan/spigot/util/LogUtil.java new file mode 100644 index 0000000..b2befca --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/LogUtil.java @@ -0,0 +1,189 @@ +package me.frep.vulcan.spigot.util; + +import java.util.ArrayList; +import java.io.InputStream; +import java.io.Reader; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.HttpURLConnection; +import java.util.Iterator; +import org.apache.commons.lang.StringUtils; +import java.text.DateFormat; +import java.io.IOException; +import java.util.zip.ZipEntry; +import java.io.OutputStream; +import java.util.zip.ZipOutputStream; +import java.io.FileOutputStream; +import java.io.FileInputStream; +import java.text.DecimalFormat; +import java.util.Date; +import me.frep.vulcan.spigot.config.Config; +import java.io.Writer; +import java.io.PrintWriter; +import java.io.FileWriter; +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import me.frep.vulcan.spigot.Vulcan; +import me.frep.vulcan.spigot.data.PlayerData; +import me.frep.vulcan.spigot.check.AbstractCheck; +import java.util.List; + +public final class LogUtil +{ + public static List leakFaggots; + + public static void logAlert(final AbstractCheck check, final PlayerData data, final String info) { + try { + final File dataFolder = Vulcan.INSTANCE.getPlugin().getDataFolder(); + final Calendar calendar = Calendar.getInstance(); + final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); + if (!dataFolder.exists()) { + dataFolder.mkdir(); + } + final File violationsFile = new File(Vulcan.INSTANCE.getPlugin().getDataFolder(), "violations.txt"); + if (!violationsFile.exists()) { + violationsFile.createNewFile(); + } + final FileWriter fw = new FileWriter(violationsFile, true); + final PrintWriter pw = new PrintWriter(fw); + final String cps = MathUtil.trim(data.getClickProcessor().getCps()); + final DateFormat date = new SimpleDateFormat("MM-dd-yyyy"); + final int maxVl = Config.MAX_VIOLATIONS.get(check.getClass().getSimpleName()); + pw.println("[" + date.format(new Date()) + "] [" + sdf.format(calendar.getTime()) + "] " + Config.LOG_FILE_ALERT_MESSAGE.replaceAll("%player%", data.getPlayer().getName()).replaceAll("%max-vl%", Integer.toString(maxVl)).replaceAll("%cps%", cps).replaceAll("%check%", check.getCheckInfo().name()).replaceAll("%world%", data.getPlayer().getWorld().getName()).replaceAll("%x%", Double.toString(data.getPositionProcessor().getX())).replaceAll("%y%", Double.toString(data.getPositionProcessor().getY())).replaceAll("%z%", Double.toString(data.getPositionProcessor().getZ())).replaceAll("%client-brand%", data.getClientBrand()).replaceAll("%complex-type%", check.getCheckInfo().complexType()).replaceAll("%tps%", new DecimalFormat("##.##").format(ServerUtil.getTPS())).replaceAll("%ping%", Integer.toString(PlayerUtil.getPing(data.getPlayer()))).replaceAll("%description%", check.getCheckInfo().description()).replaceAll("%version%", PlayerUtil.getClientVersionToString(data.getPlayer())).replaceAll("%dev%", check.getCheckInfo().experimental() ? ColorUtil.translate("*") : "").replaceAll("%vl%", Integer.toString(check.getVl())).replaceAll("%type%", Character.toString(check.getCheckInfo().type())) + " " + info); + final long length = violationsFile.length() / 1000L; + if (length > Config.MAX_LOGS_FILE_SIZE) { + final FileInputStream in = new FileInputStream(Vulcan.INSTANCE.getPlugin().getDataFolder() + File.separator + "violations.txt"); + final File logsFolder = new File(Vulcan.INSTANCE.getPlugin().getDataFolder() + File.separator + "logs"); + if (!logsFolder.exists()) { + logsFolder.mkdir(); + } + final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); + final ZipOutputStream out = new ZipOutputStream(new FileOutputStream(logsFolder + File.separator + dateFormat.format(new Date()) + ".zip")); + out.putNextEntry(new ZipEntry("violations.txt")); + final byte[] b = new byte[1024]; + int count; + while ((count = in.read(b)) > 0) { + out.write(b, 0, count); + } + out.close(); + in.close(); + violationsFile.delete(); + } + pw.flush(); + pw.close(); + } + catch (final IOException e) { + e.printStackTrace(); + } + } + + public static void logPunishment(final AbstractCheck check, final PlayerData data) { + try { + final File dataFolder = Vulcan.INSTANCE.getPlugin().getDataFolder(); + if (!dataFolder.exists()) { + dataFolder.mkdir(); + } + final File violationsFile = new File(Vulcan.INSTANCE.getPlugin().getDataFolder(), "punishments.txt"); + if (!violationsFile.exists()) { + violationsFile.createNewFile(); + } + final FileWriter fw = new FileWriter(violationsFile, true); + final PrintWriter pw = new PrintWriter(fw); + pw.println("--------------[ " + data.getPlayer().getName() + " was punished for " + StringUtils.capitalize(check.getDisplayName()) + " (Type " + Character.toUpperCase(check.getDisplayType()) + ") ]--------------"); + pw.println(""); + pw.println("Location:"); + pw.println(" - World: " + data.getPlayer().getWorld().getName()); + pw.println(" - X: " + data.getPositionProcessor().getX()); + pw.println(" - Y: " + data.getPositionProcessor().getY()); + pw.println(" - Z: " + data.getPositionProcessor().getZ()); + pw.println(""); + pw.println("Information:"); + pw.println(" - UUID: " + data.getPlayer().getUniqueId()); + pw.println(" - Keep Alive Ping: " + data.getConnectionProcessor().getKeepAlivePing()); + pw.println(" - Transaction Ping: " + data.getConnectionProcessor().getTransactionPing()); + pw.println(" - Server TPS: " + new DecimalFormat("##.##").format(ServerUtil.getTPS())); + pw.println(" - Sensitivity: " + data.getRotationProcessor().getSensitivity()); + pw.println(" - Gamemode: " + data.getPlayer().getGameMode()); + pw.println(" - Client Brand: " + data.getClientBrand()); + pw.println(" - Vehicle: " + data.getPlayer().getVehicle()); + pw.println(" - Version: " + PlayerUtil.getClientVersionToString(data.getPlayer())); + pw.println(" - Last Damage: " + data.getVelocityProcessor().getTransactionFlyingTicks() / 20.0 + " seconds ago"); + pw.println(""); + pw.println("Total Violations: " + data.getTotalViolations()); + pw.println(" - Combat Violations: " + data.getCombatViolations()); + pw.println(" - Movement Violations: " + data.getMovementViolations()); + pw.println(" - Player Violations: " + data.getPlayerViolations()); + pw.println(""); + pw.println("Misc Information:"); + pw.println(" - Since Teleport Ticks: " + data.getActionProcessor().getSinceTeleportTicks()); + pw.println(" - Since Riptide Ticks: " + data.getPositionProcessor().getSinceRiptideTicks()); + pw.println(" - Flying Delay: " + data.getConnectionProcessor().getFlyingDelay()); + pw.println(" - Since Velocity Ticks: " + data.getVelocityProcessor().getTransactionFlyingTicks()); + pw.println(" - Since Firework Ticks: " + data.getPositionProcessor().getSinceFireworkTicks()); + pw.println(" - Ticks Existed: " + data.getActionProcessor().getTicksExisted()); + pw.println(" - Since Vehicle Ticks: " + data.getPositionProcessor().getSinceVehicleTicks()); + pw.println(" - Joined: " + (System.currentTimeMillis() - data.getJoinTime()) / 1000L + " seconds ago"); + pw.println(""); + pw.println("All Violations:"); + for (final AbstractCheck check2 : data.getChecks()) { + if (check2.getVl() > 0) { + pw.println(" - " + StringUtils.capitalize(check2.getDisplayName()) + " (Type " + Character.toUpperCase(check2.getType()) + ") [VL: " + check2.getVl() + "] (" + check2.getCheckInfo().description() + ")"); + } + } + pw.println(""); + if (ServerUtil.isHigherThan1_13()) { + if (data.getPositionProcessor().getNearbyBlocksModern() != null) { + pw.println("Blocks Nearby: " + data.getPositionProcessor().getNearbyBlocksModern()); + } + } + else if (data.getPositionProcessor().getNearbyBlocks() != null) { + pw.println("Blocks Nearby: " + data.getPositionProcessor().getNearbyBlocks()); + } + if (data.getPositionProcessor().getNearbyEntities() != null) { + pw.println("Entities Nearby: " + data.getPositionProcessor().getNearbyEntities()); + } + pw.println("Potion Effects: " + data.getPlayer().getActivePotionEffects()); + pw.println("---------------------------------------------------------------------------"); + pw.println(""); + pw.println(""); + pw.flush(); + pw.close(); + } + catch (final IOException e) { + e.printStackTrace(); + } + } + + public static String getURLReturn(final String url) { + try { + final HttpURLConnection connection = (HttpURLConnection)new URL(url).openConnection(); + connection.setRequestMethod("GET"); + connection.setRequestProperty("User-Agent", "Mozilla/5.0 (compatible;VAPIv3)"); + connection.setRequestProperty("Accept", "*/*"); + final InputStream inputStream = connection.getInputStream(); + final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); + final StringBuilder stringBuilder = new StringBuilder(); + String line; + while ((line = bufferedReader.readLine()) != null) { + stringBuilder.append(line).append("\n"); + } + return stringBuilder.toString(); + } + catch (final Exception ex) { + return ""; + } + } + + private LogUtil() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + + static { + (LogUtil.leakFaggots = new ArrayList()).add("12345"); + LogUtil.leakFaggots.add("12503"); + LogUtil.leakFaggots.add("21816"); + LogUtil.leakFaggots.add("5548"); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/MathUtil.java b/src/main/java/me/frep/vulcan/spigot/util/MathUtil.java new file mode 100644 index 0000000..38e1b0d --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/MathUtil.java @@ -0,0 +1,201 @@ +package me.frep.vulcan.spigot.util; + +import org.bukkit.util.NumberConversions; +import me.frep.vulcan.spigot.data.PlayerData; +import java.math.RoundingMode; +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Map; +import java.util.function.Supplier; +import java.util.function.Function; +import java.util.Comparator; +import me.frep.vulcan.spigot.util.type.Tuple; +import java.util.HashMap; +import java.util.List; +import java.util.Collections; +import com.google.common.collect.Lists; +import java.util.Iterator; +import java.util.Collection; +import java.text.DecimalFormat; + +public final class MathUtil +{ + public static final double EXPANDER; + + public static double hypot(final double x, final double z) { + return Math.sqrt(x * x + z * z); + } + + public static double magnitude(final double x, final double y, final double z) { + return Math.sqrt(x * x + y * y + z * z); + } + + public static String trim(final double x) { + return new DecimalFormat("#.##").format(x); + } + + public static float distanceBetweenAngles(final float alpha, final float beta) { + final float alphaX = alpha % 360.0f; + final float betaX = beta % 360.0f; + final float delta = Math.abs(alphaX - betaX); + return (float)Math.abs(Math.min(360.0 - delta, delta)); + } + + public static double getVariance(final Collection data) { + int count = 0; + double sum = 0.0; + double variance = 0.0; + for (final Number number : data) { + sum += number.doubleValue(); + ++count; + } + final double average = sum / count; + for (final Number number : data) { + variance += Math.pow(number.doubleValue() - average, 2.0); + } + return variance; + } + + public static double getStandardDeviation(final Collection data) { + final double variance = getVariance(data); + return Math.sqrt(variance); + } + + public static double getSkewness(final Collection data) { + double sum = 0.0; + int count = 0; + final List numbers = Lists.newArrayList(); + for (final Number number : data) { + sum += number.doubleValue(); + ++count; + numbers.add(number.doubleValue()); + } + Collections.sort(numbers); + final double mean = sum / count; + final double median = (count % 2 != 0) ? numbers.get(count / 2) : ((numbers.get((count - 1) / 2) + numbers.get(count / 2)) / 2.0); + final double variance = getVariance(data); + return 3.0 * (mean - median) / variance; + } + + public static double getAverage(final Collection data) { + if (data == null || data.isEmpty()) { + return 0.0; + } + double sum = 0.0; + for (final Number number : data) { + sum += number.doubleValue(); + } + return sum / data.size(); + } + + public static double getKurtosis(final Collection data) { + double sum = 0.0; + int count = 0; + for (final Number number : data) { + sum += number.doubleValue(); + ++count; + } + if (count < 3.0) { + return 0.0; + } + final double efficiencyFirst = count * (count + 1.0) / ((count - 1.0) * (count - 2.0) * (count - 3.0)); + final double efficiencySecond = 3.0 * Math.pow(count - 1.0, 2.0) / ((count - 2.0) * (count - 3.0)); + final double average = sum / count; + double variance = 0.0; + double varianceSquared = 0.0; + for (final Number number2 : data) { + variance += Math.pow(average - number2.doubleValue(), 2.0); + varianceSquared += Math.pow(average - number2.doubleValue(), 4.0); + } + return efficiencyFirst * (varianceSquared / Math.pow(variance / sum, 2.0)) - efficiencySecond; + } + public static double round(final double value, final int places) { + if (places < 0) { + throw new IllegalArgumentException(); + } + return new BigDecimal(value).setScale(places, RoundingMode.HALF_UP).doubleValue(); + } + + public static int getMode(final Collection array) { + int mode = (int)array.toArray()[0]; + int maxCount = 0; + for (final Number value : array) { + int count = 1; + for (final Number i : array) { + if (i.equals(value)) { + ++count; + } + if (count > maxCount) { + mode = (int)value; + maxCount = count; + } + } + } + return mode; + } + + private static double getMedian(final List data) { + if (data.size() % 2 == 0) { + return (data.get(data.size() / 2) + data.get(data.size() / 2 - 1)) / 2.0; + } + return data.get(data.size() / 2); + } + + public static boolean isExponentiallySmall(final Number number) { + return number.doubleValue() < 1.0 && Double.toString(number.doubleValue()).contains("E"); + } + + public static long getGcd(final long current, final long previous) { + return (previous <= 16384L) ? current : getGcd(previous, current % previous); + } + + public static double getGcd(final double a, final double b) { + if (a < b) { + return getGcd(b, a); + } + if (Math.abs(b) < 0.001) { + return a; + } + return getGcd(b, a - Math.floor(a / b) * b); + } + + public static double angleOf(final double minX, final double minZ, final double maxX, final double maxZ) { + final double deltaY = minZ - maxZ; + final double deltaX = maxX - minX; + final double result = Math.toDegrees(Math.atan2(deltaY, deltaX)); + return (result < 0.0) ? (360.0 + result) : result; + } + + public static double getDistanceBetweenAngles360(final double alpha, final double beta) { + final double abs = Math.abs(alpha % 360.0 - beta % 360.0); + return Math.abs(Math.min(360.0 - abs, abs)); + } + + public static double getDistanceBetweenAngles360Raw(final double alpha, final double beta) { + return Math.abs(alpha % 360.0 - beta % 360.0); + } + + public static double getCps(final Collection data) { + return 20.0 / getAverage(data) * 50.0; + } + + public static int getDuplicates(final Collection data) { + return (int)(data.size() - data.stream().distinct().count()); + } + + public static int getDistinct(final Collection data) { + return (int)data.stream().distinct().count(); + } + + public static int getPingInTicks(final PlayerData data) { + return NumberConversions.floor(data.getConnectionProcessor().getTransactionPing() / 50.0) + 3; + } + + private MathUtil() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + + static { + EXPANDER = Math.pow(2.0, 24.0); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/PlayerUtil.java b/src/main/java/me/frep/vulcan/spigot/util/PlayerUtil.java new file mode 100644 index 0000000..380a59d --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/PlayerUtil.java @@ -0,0 +1,476 @@ +package me.frep.vulcan.spigot.util; + +import org.bukkit.World; +import org.bukkit.plugin.Plugin; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import io.github.retrooper.packetevents.packetwrappers.play.out.helditemslot.WrappedPacketOutHeldItemSlot; +import java.util.concurrent.ThreadLocalRandom; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.block.BlockFace; +import java.util.function.Predicate; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.entity.LivingEntity; +import java.util.Iterator; +import org.bukkit.potion.PotionEffect; +import java.util.LinkedList; +import java.util.List; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.Material; +import io.github.retrooper.packetevents.packetwrappers.play.out.ping.WrappedPacketOutPing; +import io.github.retrooper.packetevents.packetwrappers.play.out.transaction.WrappedPacketOutTransaction; +import me.frep.vulcan.spigot.data.PlayerData; +import io.github.retrooper.packetevents.packetwrappers.api.SendableWrapper; +import io.github.retrooper.packetevents.PacketEvents; +import io.github.retrooper.packetevents.utils.player.ClientVersion; +import org.bukkit.entity.Player; + +public final class PlayerUtil +{ + public static ClientVersion getClientVersion(final Player player) { + return PacketEvents.get().getPlayerUtils().getClientVersion(player); + } + + public static String getClientVersionToString(final Player player) { + if (getClientVersion(player) == null || player.hasMetadata("NPC") || player.hasMetadata("npc")) { + return "Unresolved"; + } + return getClientVersion(player).toString().replaceAll("v_", "").replaceAll("_", "."); + } + + public static boolean isHigherThan1_9(final Player player) { + return getClientVersion(player) != null && getClientVersion(player) != ClientVersion.UNRESOLVED && getClientVersion(player).isNewerThanOrEquals(ClientVersion.v_1_9); + } + + public static boolean isHigherThan1_13(final Player player) { + return getClientVersion(player) != null && getClientVersion(player) != ClientVersion.UNRESOLVED && getClientVersion(player).isNewerThanOrEquals(ClientVersion.v_1_13); + } + + public static int getPing(final Player player) { + return PacketEvents.get().getPlayerUtils().getNMSPing(player); + } + + public static void addChannel(final Player player, final String channel) { + try { + player.getClass().getMethod("addChannel", String.class).invoke(player, channel); + } + catch (final Exception e) { + e.printStackTrace(); + } + } + + public static void sendPacket(final Player player, final SendableWrapper wrapper) { + PacketEvents.get().getPlayerUtils().sendPacket(player, wrapper); + } + + public static boolean is1_17(final PlayerData data) { + return data.getClientVersion().isNewerThanOrEquals(ClientVersion.v_1_17); + } + + public static boolean is1_9(final PlayerData data) { + return data.getClientVersion().isNewerThan(ClientVersion.v_1_9); + } + + public static boolean is1_13(final PlayerData data) { + return data.getClientVersion().isNewerThanOrEquals(ClientVersion.v_1_13); + } + + public static void sendTransaction(final Player player, final short id) { + if (player.hasMetadata("NPC") || player.hasMetadata("npc")) { + return; + } + sendPacket(player, new WrappedPacketOutTransaction(0, id, false)); + } + + public static void sendPing(final Player player, final int id) { + if (player.hasMetadata("NPC") || player.hasMetadata("npc")) { + return; + } + sendPacket(player, new WrappedPacketOutPing(id)); + } + + public static boolean isSwimming(final Player player) { + return ServerUtil.isHigherThan1_13() && player.isSwimming(); + } + + public static boolean isFullyStuckModern(final PlayerData data) { + return data.getPositionProcessor().getNearbyBlocksModern() != null && !data.getPositionProcessor().getNearbyBlocksModern().isEmpty() && data.getPositionProcessor().getNearbyBlocksModern().get(16).isSolid() && data.getPositionProcessor().getNearbyBlocksModern().get(19).isSolid(); + } + + public static boolean isFullyStuck(final PlayerData data) { + return data.getPositionProcessor().getNearbyBlocks() != null && !data.getPositionProcessor().getNearbyBlocks().isEmpty() && data.getPositionProcessor().getNearbyBlocks().get(16).isSolid() && data.getPositionProcessor().getNearbyBlocks().get(19).isSolid(); + } + + public static boolean isPartiallyStuckModern(final PlayerData data) { + return data.getPositionProcessor().getNearbyBlocksModern() != null && !data.getPositionProcessor().getNearbyBlocksModern().isEmpty() && (data.getPositionProcessor().getNearbyBlocksModern().get(16).isSolid() || data.getPositionProcessor().getNearbyBlocksModern().get(19).isSolid()); + } + + public static boolean isPartiallyStuck(final PlayerData data) { + return data.getPositionProcessor().getNearbyBlocks() != null && !data.getPositionProcessor().getNearbyBlocks().isEmpty() && (data.getPositionProcessor().getNearbyBlocks().get(16).isSolid() || data.getPositionProcessor().getNearbyBlocks().get(19).isSolid()); + } + + public static boolean hasDolphinsGrace(final Player player) { + return ServerUtil.isHigherThan1_13() && player.hasPotionEffect(PotionEffectType.DOLPHINS_GRACE); + } + + public static boolean isInBubbleColumnModern(final PlayerData data) { + return data.getPositionProcessor().getNearbyBlocksModern() != null && !data.getPositionProcessor().getNearbyBlocksModern().isEmpty() && (BlockUtil.isBubbleColumn(data.getPositionProcessor().getNearbyBlocksModern().get(16)) || BlockUtil.isBubbleColumn(data.getPositionProcessor().getNearbyBlocksModern().get(19))); + } + + public static double getYawDiff(final Player damager, final Player victim) { + return Math.abs(180.0f - Math.abs(damager.getLocation().getYaw() - victim.getLocation().getYaw())); + } + + public static boolean isInBubbleColumn(final PlayerData data) { + return data.getPositionProcessor().getNearbyBlocks() != null && !data.getPositionProcessor().getNearbyBlocks().isEmpty() && (BlockUtil.isBubbleColumn(data.getPositionProcessor().getNearbyBlocks().get(16)) || BlockUtil.isBubbleColumn(data.getPositionProcessor().getNearbyBlocks().get(19))); + } + + public static List getBlocksBelowModern(final PlayerData data) { + final List blocksBelow = new LinkedList(); + final List nearbyBlocksModern = data.getPositionProcessor().getNearbyBlocksModern(); + if (nearbyBlocksModern == null || nearbyBlocksModern.isEmpty()) { + return blocksBelow; + } + blocksBelow.add(nearbyBlocksModern.get(0)); + blocksBelow.add(nearbyBlocksModern.get(1)); + blocksBelow.add(nearbyBlocksModern.get(2)); + blocksBelow.add(nearbyBlocksModern.get(12)); + blocksBelow.add(nearbyBlocksModern.get(13)); + blocksBelow.add(nearbyBlocksModern.get(14)); + blocksBelow.add(nearbyBlocksModern.get(24)); + blocksBelow.add(nearbyBlocksModern.get(25)); + blocksBelow.add(nearbyBlocksModern.get(26)); + return blocksBelow; + } + + public static List getBlocksAboveGlitchedModern(final PlayerData data) { + final List glitchedBlocksAbove = new LinkedList(); + final List nearbyBlocksModern = data.getPositionProcessor().getNearbyBlocksModern(); + if (nearbyBlocksModern == null || nearbyBlocksModern.isEmpty()) { + return glitchedBlocksAbove; + } + glitchedBlocksAbove.add(nearbyBlocksModern.get(6)); + glitchedBlocksAbove.add(nearbyBlocksModern.get(7)); + glitchedBlocksAbove.add(nearbyBlocksModern.get(8)); + glitchedBlocksAbove.add(nearbyBlocksModern.get(18)); + glitchedBlocksAbove.add(nearbyBlocksModern.get(19)); + glitchedBlocksAbove.add(nearbyBlocksModern.get(20)); + glitchedBlocksAbove.add(nearbyBlocksModern.get(30)); + glitchedBlocksAbove.add(nearbyBlocksModern.get(31)); + glitchedBlocksAbove.add(nearbyBlocksModern.get(32)); + return glitchedBlocksAbove; + } + + public static List getBlocksAboveGlitchedLegacy(final PlayerData data) { + final List glitchedBlocksAbove = new LinkedList(); + final List nearbyBlocks = data.getPositionProcessor().getNearbyBlocks(); + if (nearbyBlocks == null || nearbyBlocks.isEmpty()) { + return glitchedBlocksAbove; + } + glitchedBlocksAbove.add(nearbyBlocks.get(6)); + glitchedBlocksAbove.add(nearbyBlocks.get(7)); + glitchedBlocksAbove.add(nearbyBlocks.get(8)); + glitchedBlocksAbove.add(nearbyBlocks.get(18)); + glitchedBlocksAbove.add(nearbyBlocks.get(19)); + glitchedBlocksAbove.add(nearbyBlocks.get(20)); + glitchedBlocksAbove.add(nearbyBlocks.get(30)); + glitchedBlocksAbove.add(nearbyBlocks.get(31)); + glitchedBlocksAbove.add(nearbyBlocks.get(32)); + return glitchedBlocksAbove; + } + + public static List getBlocksBelow(final PlayerData data) { + final List blocksBelow = new LinkedList(); + final List nearbyBlocks = data.getPositionProcessor().getNearbyBlocks(); + if (nearbyBlocks == null || nearbyBlocks.isEmpty()) { + return blocksBelow; + } + blocksBelow.add(nearbyBlocks.get(0)); + blocksBelow.add(nearbyBlocks.get(1)); + blocksBelow.add(nearbyBlocks.get(2)); + blocksBelow.add(nearbyBlocks.get(12)); + blocksBelow.add(nearbyBlocks.get(13)); + blocksBelow.add(nearbyBlocks.get(14)); + blocksBelow.add(nearbyBlocks.get(24)); + blocksBelow.add(nearbyBlocks.get(25)); + blocksBelow.add(nearbyBlocks.get(26)); + return blocksBelow; + } + + public static List getBlocksAroundModern(final PlayerData data) { + final List blocksAround = new LinkedList(); + final List nearbyBlocksModern = data.getPositionProcessor().getNearbyBlocksModern(); + if (nearbyBlocksModern == null || nearbyBlocksModern.isEmpty()) { + return blocksAround; + } + blocksAround.add(nearbyBlocksModern.get(3)); + blocksAround.add(nearbyBlocksModern.get(4)); + blocksAround.add(nearbyBlocksModern.get(5)); + blocksAround.add(nearbyBlocksModern.get(6)); + blocksAround.add(nearbyBlocksModern.get(7)); + blocksAround.add(nearbyBlocksModern.get(8)); + blocksAround.add(nearbyBlocksModern.get(15)); + blocksAround.add(nearbyBlocksModern.get(16)); + blocksAround.add(nearbyBlocksModern.get(17)); + blocksAround.add(nearbyBlocksModern.get(18)); + blocksAround.add(nearbyBlocksModern.get(19)); + blocksAround.add(nearbyBlocksModern.get(20)); + blocksAround.add(nearbyBlocksModern.get(27)); + blocksAround.add(nearbyBlocksModern.get(28)); + blocksAround.add(nearbyBlocksModern.get(29)); + blocksAround.add(nearbyBlocksModern.get(30)); + blocksAround.add(nearbyBlocksModern.get(31)); + blocksAround.add(nearbyBlocksModern.get(32)); + return blocksAround; + } + + public static List getBlocksAround(final PlayerData data) { + final List blocksAround = new LinkedList(); + final List nearbyBlocks = data.getPositionProcessor().getNearbyBlocks(); + if (nearbyBlocks == null || nearbyBlocks.isEmpty()) { + return blocksAround; + } + blocksAround.add(nearbyBlocks.get(3)); + blocksAround.add(nearbyBlocks.get(4)); + blocksAround.add(nearbyBlocks.get(5)); + blocksAround.add(nearbyBlocks.get(6)); + blocksAround.add(nearbyBlocks.get(7)); + blocksAround.add(nearbyBlocks.get(8)); + blocksAround.add(nearbyBlocks.get(15)); + blocksAround.add(nearbyBlocks.get(16)); + blocksAround.add(nearbyBlocks.get(17)); + blocksAround.add(nearbyBlocks.get(18)); + blocksAround.add(nearbyBlocks.get(19)); + blocksAround.add(nearbyBlocks.get(20)); + blocksAround.add(nearbyBlocks.get(27)); + blocksAround.add(nearbyBlocks.get(28)); + blocksAround.add(nearbyBlocks.get(29)); + blocksAround.add(nearbyBlocks.get(30)); + blocksAround.add(nearbyBlocks.get(31)); + blocksAround.add(nearbyBlocks.get(32)); + return blocksAround; + } + + public static List getBlocksAbove(final PlayerData data) { + final List blocksAbove = new LinkedList(); + final List nearbyBlocks = data.getPositionProcessor().getNearbyBlocks(); + if (nearbyBlocks == null || nearbyBlocks.isEmpty()) { + return blocksAbove; + } + blocksAbove.add(nearbyBlocks.get(9)); + blocksAbove.add(nearbyBlocks.get(10)); + blocksAbove.add(nearbyBlocks.get(11)); + blocksAbove.add(nearbyBlocks.get(21)); + blocksAbove.add(nearbyBlocks.get(22)); + blocksAbove.add(nearbyBlocks.get(23)); + blocksAbove.add(nearbyBlocks.get(33)); + blocksAbove.add(nearbyBlocks.get(34)); + blocksAbove.add(nearbyBlocks.get(35)); + return blocksAbove; + } + + public static List getBlocksAboveModern(final PlayerData data) { + final List blocksAbove = new LinkedList(); + final List nearbyBlocksModern = data.getPositionProcessor().getNearbyBlocksModern(); + if (nearbyBlocksModern == null || nearbyBlocksModern.isEmpty()) { + return blocksAbove; + } + blocksAbove.add(nearbyBlocksModern.get(9)); + blocksAbove.add(nearbyBlocksModern.get(10)); + blocksAbove.add(nearbyBlocksModern.get(11)); + blocksAbove.add(nearbyBlocksModern.get(21)); + blocksAbove.add(nearbyBlocksModern.get(22)); + blocksAbove.add(nearbyBlocksModern.get(23)); + blocksAbove.add(nearbyBlocksModern.get(33)); + blocksAbove.add(nearbyBlocksModern.get(34)); + blocksAbove.add(nearbyBlocksModern.get(35)); + return blocksAbove; + } + + public static boolean isRiptiding(final Player player) { + return ServerUtil.isHigherThan1_13() && player.isRiptiding(); + } + + public static boolean isGliding(final Player player) { + return ServerUtil.isHigherThan1_9() && player.isGliding(); + } + + public static int getPotionLevel(final Player player, final PotionEffectType effect) { + final int effectId = effect.getId(); + for (final PotionEffect active : player.getActivePotionEffects()) { + if (effectId == active.getType().getId()) { + return active.getAmplifier() + 1; + } + } + return 0; + } + + public static double getBaseSpeed(final PlayerData data) { + double speed = 0.36 + (data.getActionProcessor().getSpeedAmplifier() * 0.0675f + (data.getPositionProcessor().getWalkSpeed() - 0.2f) * 3.5f); + if (speed < 0.36) { + speed = 0.36 + data.getActionProcessor().getSpeedAmplifier() * 0.0675f; + } + return speed; + } + + public static double getBaseSpeedElytra(final PlayerData data) { + double speed = 0.4 + (data.getActionProcessor().getSpeedAmplifier() * 0.0675f + (data.getPositionProcessor().getWalkSpeed() - 0.2f) * 3.5f); + if (speed < 0.36) { + speed = 0.36 + data.getActionProcessor().getSpeedAmplifier() * 0.0675f; + } + return speed; + } + + public static boolean isOnIceModern(final PlayerData data) { + return data.getPositionProcessor().getNearbyBlocksModern() != null && !data.getPositionProcessor().getNearbyBlocksModern().isEmpty() && (BlockUtil.isIce(data.getPositionProcessor().getNearbyBlocksModern().get(13)) || BlockUtil.isIce(data.getPositionProcessor().getBlockBelow2Modern()) || BlockUtil.isIce(data.getPositionProcessor().getBlockBelow3Modern())); + } + + public static boolean isOnIce(final PlayerData data) { + return data.getPositionProcessor().getNearbyBlocks() != null && !data.getPositionProcessor().getNearbyBlocks().isEmpty() && (BlockUtil.isIce(data.getPositionProcessor().getNearbyBlocks().get(13)) || BlockUtil.isIce(data.getPositionProcessor().getBlockBelow2()) || BlockUtil.isIce(data.getPositionProcessor().getBlockBelow3())); + } + + public static boolean isInWebModern(final PlayerData data) { + return data.getPositionProcessor().getNearbyBlocksModern() != null && !data.getPositionProcessor().getNearbyBlocksModern().isEmpty() && (BlockUtil.isWeb(data.getPositionProcessor().getNearbyBlocksModern().get(16)) || BlockUtil.isWeb(data.getPositionProcessor().getNearbyBlocksModern().get(19))); + } + + public static boolean isInWeb(final PlayerData data) { + return data.getPositionProcessor().getNearbyBlocks() != null && !data.getPositionProcessor().getNearbyBlocks().isEmpty() && (BlockUtil.isWeb(data.getPositionProcessor().getNearbyBlocks().get(16)) || BlockUtil.isWeb(data.getPositionProcessor().getNearbyBlocks().get(19))); + } + + public static boolean isInLiquidModern(final PlayerData data) { + return data.getPositionProcessor().getNearbyBlocksModern() != null && !data.getPositionProcessor().getNearbyBlocksModern().isEmpty() && (BlockUtil.isLiquid(data.getPositionProcessor().getNearbyBlocksModern().get(16)) || BlockUtil.isLiquid(data.getPositionProcessor().getNearbyBlocksModern().get(19))); + } + + public static boolean isInLiquid(final PlayerData data) { + return data.getPositionProcessor().getNearbyBlocks() != null && !data.getPositionProcessor().getNearbyBlocks().isEmpty() && (BlockUtil.isLiquid(data.getPositionProcessor().getNearbyBlocks().get(16)) || BlockUtil.isLiquid(data.getPositionProcessor().getNearbyBlocks().get(19))); + } + + public static boolean isOnClimbableModern(final PlayerData data) { + return data.getPositionProcessor().getNearbyBlocksModern() != null && !data.getPositionProcessor().getNearbyBlocksModern().isEmpty() && BlockUtil.isClimbable(data.getPositionProcessor().getNearbyBlocksModern().get(16)) && BlockUtil.isClimbable(data.getPositionProcessor().getNearbyBlocksModern().get(19)); + } + + public static boolean isOnClimbable(final PlayerData data) { + return data.getPositionProcessor().getNearbyBlocks() != null && !data.getPositionProcessor().getNearbyBlocks().isEmpty() && BlockUtil.isClimbable(data.getPositionProcessor().getNearbyBlocks().get(16)) && BlockUtil.isClimbable(data.getPositionProcessor().getNearbyBlocks().get(19)); + } + + public static int getSpeed(final LivingEntity entity) { + for (final PotionEffect effect : entity.getActivePotionEffects()) { + if (effect.getType().toString().contains("SPEED")) { + return effect.getAmplifier() + 1; + } + } + return 0; + } + + public static double getBaseGroundSpeed(final PlayerData data) { + double speed = 0.2975 + data.getActionProcessor().getSpeedAmplifier() * 0.075f + (data.getPositionProcessor().getWalkSpeed() - 0.2f) * 3.5; + if (speed < 0.2975) { + speed = 0.2975 + data.getActionProcessor().getSpeedAmplifier() * 0.075f; + } + return speed; + } + + public static boolean isHoldingItem(final PlayerData data) { + return ServerUtil.isHigherThan1_9() && (data.getPlayer().getInventory().getItemInMainHand().getType() != Material.AIR || data.getPlayer().getInventory().getItemInOffHand().getType() != Material.AIR); + } + + public static double getBaseGroundSpeedElytra(final PlayerData data) { + double speed = 0.32 + data.getActionProcessor().getSpeedAmplifier() * 0.08f + (data.getPositionProcessor().getWalkSpeed() - 0.2f) * 3.5; + if (speed < 0.32) { + speed = 0.32; + } + return speed; + } + + public static boolean isBridging(final BlockPlaceEvent event) { + final Player player = event.getPlayer(); + if (!player.getItemInHand().getType().isSolid() || BlockUtil.isSand(event.getBlock().getType()) || BlockUtil.isGravel(event.getBlock().getType())) { + return false; + } + final PlayerData data = Vulcan.INSTANCE.getPlayerDataManager().getPlayerData(player); + if (data != null) { + Material below2; + if (ServerUtil.isHigherThan1_13()) { + below2 = data.getPositionProcessor().getBlockBelow2Modern(); + } + else { + below2 = data.getPositionProcessor().getBlockBelow2(); + } + final BlockFace face = event.getBlockAgainst().getFace(event.getBlock()); + final double blockX = event.getBlockAgainst().getX(); + final double blockY = event.getBlockAgainst().getY(); + final double blockZ = event.getBlockAgainst().getZ(); + final double playerX = data.getPlayer().getLocation().getX(); + final double playerY = data.getPlayer().getLocation().getY(); + final double playerZ = data.getPlayer().getLocation().getZ(); + final double distance = MathUtil.hypot(Math.abs(blockX - playerX), Math.abs(blockZ - playerZ)); + final List blocksBelow = data.getPositionProcessor().getBlocksBelow(); + if (blocksBelow == null) { + return false; + } + final int airBelow = (int)blocksBelow.stream().filter(BlockUtil::isAir).count(); + if (below2 != null && face != null && face != BlockFace.UP) { + return BlockUtil.isAir(below2) && distance < 2.25 && blockY < playerY && airBelow > 6; + } + } + return false; + } + + public static boolean isFullySubmergedModern(final PlayerData data) { + return data.getPositionProcessor().getNearbyBlocksModern() != null && !data.getPositionProcessor().getNearbyBlocksModern().isEmpty() && BlockUtil.isLiquid(data.getPositionProcessor().getNearbyBlocksModern().get(16)) && BlockUtil.isLiquid(data.getPositionProcessor().getNearbyBlocksModern().get(19)); + } + + public static boolean isFullySubmerged(final PlayerData data) { + return data.getPositionProcessor().getNearbyBlocks() != null && !data.getPositionProcessor().getNearbyBlocks().isEmpty() && BlockUtil.isLiquid(data.getPositionProcessor().getNearbyBlocks().get(16)) && BlockUtil.isLiquid(data.getPositionProcessor().getNearbyBlocks().get(19)); + } + + public static boolean isHoldingTridentWithRiptide(final Player player) { + return ServerUtil.isHigherThan1_13() && ((player.getInventory().getItemInMainHand().getType().toString().contains("TRIDENT") && player.getInventory().getItemInMainHand().getEnchantmentLevel(Enchantment.RIPTIDE) > 0) || (player.getInventory().getItemInOffHand().getType().toString().contains("TRIDENT") && player.getInventory().getItemInOffHand().getEnchantmentLevel(Enchantment.RIPTIDE) > 0)); + } + + public static void shuffleHotbar(final Player player) { + final int random = ThreadLocalRandom.current().nextInt(8); + sendPacket(player, new WrappedPacketOutHeldItemSlot(random)); + } + + public static float getBaseSpeed(final PlayerData data, final float base) { + final float speed = base + (data.getActionProcessor().getSpeedAmplifier() * 0.0675f + (data.getPositionProcessor().getWalkSpeed() - 0.2f) * 3.5f); + if (speed < base) { + return base + data.getActionProcessor().getSpeedAmplifier() * 0.0675f; + } + return base; + } + + public static void rotateRandomly(final Player player) { + final World world = player.getWorld(); + final double x = player.getLocation().getX(); + final double y = player.getLocation().getY(); + final double z = player.getLocation().getZ(); + final float randomYaw = (float)ThreadLocalRandom.current().nextDouble(360.0) - 180.0f; + final float randomPitch = (float)ThreadLocalRandom.current().nextDouble(180.0) - 90.0f; + final Location location = new Location(world, x, y, z, randomYaw, randomPitch); + Bukkit.getScheduler().runTask(Vulcan.INSTANCE.getPlugin(), () -> player.teleport(location, PlayerTeleportEvent.TeleportCause.UNKNOWN)); + } + + public static boolean isWearingNetherite(final Player player) { + if (!ServerUtil.isHigherThan1_16()) { + return false; + } + if (player.getInventory().getHelmet() != null) { + return player.getInventory().getHelmet().getType() == Material.NETHERITE_HELMET; + } + if (player.getInventory().getChestplate() != null) { + return player.getInventory().getChestplate().getType() == Material.NETHERITE_CHESTPLATE; + } + if (player.getInventory().getLeggings() != null) { + return player.getInventory().getLeggings().getType() == Material.NETHERITE_LEGGINGS; + } + return player.getInventory().getBoots() != null && player.getInventory().getBoots().getType() == Material.NETHERITE_BOOTS; + } + + private PlayerUtil() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/ServerUtil.java b/src/main/java/me/frep/vulcan/spigot/util/ServerUtil.java new file mode 100644 index 0000000..bf98757 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/ServerUtil.java @@ -0,0 +1,134 @@ +package me.frep.vulcan.spigot.util; + +import org.bukkit.command.CommandSender; +import org.bukkit.Bukkit; +import me.frep.vulcan.spigot.config.Config; +import io.github.retrooper.packetevents.utils.server.ServerVersion; +import java.util.logging.Level; +import me.frep.vulcan.spigot.Vulcan; +import io.github.retrooper.packetevents.PacketEvents; + +public final class ServerUtil +{ + private static final boolean higherThan1_7; + private static final boolean higherThan1_8; + private static final boolean higherThan1_9; + private static final boolean lowerThan1_13; + private static final boolean lowerThan1_8; + private static final boolean lowerThan1_9; + private static final boolean higherThan1_13; + private static final boolean higherThan1_16; + private static final boolean higherThan1_12; + private static final boolean higherThan1_11; + private static final boolean higherThan1_17; + private static final boolean higherThan1_14; + private static final boolean higherThan1_18; + private static final boolean higherThan1_19; + + public static double getTPS() { + return Math.min(20.0, PacketEvents.get().getServerUtils().getTPS()); + } + + public static void logError(final String message) { + Vulcan.INSTANCE.getLogger().log(Level.INFO, ColorUtil.translate(message)); + } + + public static void log(final String message) { + Vulcan.INSTANCE.getLogger().log(Level.INFO, ColorUtil.translate(message)); + } + + public static ServerVersion getServerVersion() { + return PacketEvents.get().getServerUtils().getVersion(); + } + + public static boolean isHigherThan1_17() { + return ServerUtil.higherThan1_17; + } + + public static boolean isHigherThan1_19() { + return ServerUtil.higherThan1_19; + } + + public static boolean isHigherThan1_14() { + return ServerUtil.higherThan1_14; + } + + public static boolean isHigherThan1_11() { + return ServerUtil.higherThan1_11; + } + + public static boolean isHigherThan1_7() { + return ServerUtil.higherThan1_7; + } + + public static boolean isLowerThan1_9() { + return ServerUtil.lowerThan1_9; + } + + public static boolean isHigherThan1_8() { + return ServerUtil.higherThan1_8; + } + + public static boolean isHigherThan1_13() { + return ServerUtil.higherThan1_13; + } + + public static boolean isHigherThan1_16() { + return ServerUtil.higherThan1_16; + } + + public static boolean isHigherThan1_9() { + return ServerUtil.higherThan1_9; + } + + public static boolean isLowerThan1_13() { + return ServerUtil.lowerThan1_13; + } + + public static boolean isLowerThan1_8() { + return ServerUtil.lowerThan1_8; + } + + public static boolean isHigherThan1_18() { + return ServerUtil.higherThan1_18; + } + + public static void debug(final Object object) { + if (Config.DEBUG) { + broadcast("&c[!] &7" + object); + } + } + + public static void dispatchCommand(final String command) { + Bukkit.dispatchCommand(Bukkit.getConsoleSender(), ColorUtil.translate(command)); + } + + public static void broadcast(final String message) { + Bukkit.broadcastMessage(ColorUtil.translate(message)); + } + + public static boolean isHigherThan1_12() { + return ServerUtil.higherThan1_12; + } + + private ServerUtil() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + + static { + higherThan1_7 = getServerVersion().isHigherThan(ServerVersion.v_1_7_10); + higherThan1_8 = getServerVersion().isHigherThanOrEquals(ServerVersion.v_1_8); + higherThan1_9 = getServerVersion().isHigherThanOrEquals(ServerVersion.v_1_9); + lowerThan1_13 = getServerVersion().isLowerThan(ServerVersion.v_1_13); + lowerThan1_8 = getServerVersion().isLowerThan(ServerVersion.v_1_8); + lowerThan1_9 = getServerVersion().isOlderThan(ServerVersion.v_1_9); + higherThan1_13 = getServerVersion().isHigherThan(ServerVersion.v_1_13); + higherThan1_16 = getServerVersion().isNewerThanOrEquals(ServerVersion.v_1_16); + higherThan1_12 = getServerVersion().isHigherThanOrEquals(ServerVersion.v_1_12); + higherThan1_11 = getServerVersion().isNewerThanOrEquals(ServerVersion.v_1_11); + higherThan1_17 = getServerVersion().isNewerThanOrEquals(ServerVersion.v_1_17); + higherThan1_14 = getServerVersion().isNewerThanOrEquals(ServerVersion.v_1_14); + higherThan1_18 = getServerVersion().isNewerThanOrEquals(ServerVersion.v_1_18); + higherThan1_19 = getServerVersion().isNewerThanOrEquals(ServerVersion.v_1_19); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/StreamUtil.java b/src/main/java/me/frep/vulcan/spigot/util/StreamUtil.java new file mode 100644 index 0000000..d904100 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/StreamUtil.java @@ -0,0 +1,36 @@ +package me.frep.vulcan.spigot.util; + +import java.util.Iterator; +import java.util.function.Predicate; +import java.util.Collection; + +public final class StreamUtil +{ + public static boolean anyMatch(final Collection collection, final Predicate condition) { + if (condition == null) { + return false; + } + for (final T object : collection) { + if (condition.test(object)) { + return true; + } + } + return false; + } + + public static boolean allMatch(final Collection collection, final Predicate condition) { + if (condition == null) { + return false; + } + for (final T object : collection) { + if (!condition.test(object)) { + return false; + } + } + return true; + } + + private StreamUtil() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/TimeUtil.java b/src/main/java/me/frep/vulcan/spigot/util/TimeUtil.java new file mode 100644 index 0000000..7c89b92 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/TimeUtil.java @@ -0,0 +1,44 @@ +package me.frep.vulcan.spigot.util; + +import java.io.InputStream; +import java.io.Reader; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.HttpURLConnection; +import me.frep.vulcan.spigot.Vulcan; + +public final class TimeUtil +{ + public static boolean elapsed(final int from, final int required) { + return Vulcan.INSTANCE.getTickManager().getTicks() - from > required; + } + + public static boolean elapsed(final long from, final long required) { + return System.currentTimeMillis() - from > required; + } + + public static String getURLReturn(final String url) { + try { + final HttpURLConnection connection = (HttpURLConnection)new URL(url).openConnection(); + connection.setRequestMethod("GET"); + connection.setRequestProperty("User-Agent", "Mozilla/5.0 (compatible;VAPIv3)"); + connection.setRequestProperty("Accept", "*/*"); + final InputStream inputStream = connection.getInputStream(); + final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); + final StringBuilder stringBuilder = new StringBuilder(); + String line; + while ((line = bufferedReader.readLine()) != null) { + stringBuilder.append(line).append("\n"); + } + return stringBuilder.toString(); + } + catch (final Exception ex) { + return ""; + } + } + + private TimeUtil() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/boundingbox/BoundingBox.java b/src/main/java/me/frep/vulcan/spigot/util/boundingbox/BoundingBox.java new file mode 100644 index 0000000..c7476f3 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/boundingbox/BoundingBox.java @@ -0,0 +1,271 @@ +package me.frep.vulcan.spigot.util.boundingbox; + +import me.frep.vulcan.spigot.util.nms.EnumFacing; +import me.frep.vulcan.spigot.util.reach.MovingPoint; +import me.frep.vulcan.spigot.util.reach.Point; +import java.util.List; +import java.util.Collection; +import me.frep.vulcan.spigot.util.StreamUtil; +import me.frep.vulcan.spigot.util.BlockUtil; +import java.util.LinkedList; +import org.bukkit.Material; +import java.util.function.Predicate; +import org.bukkit.World; +import org.bukkit.Location; + +public final class BoundingBox +{ + private double minX; + private double minY; + private double minZ; + private double maxX; + private double maxY; + private double maxZ; + private final long timestamp; + + public BoundingBox(final double x, final double y, final double z) { + this(x, x, y, y, z, z); + } + + public BoundingBox(final double minX, final double maxX, final double minY, final double maxY, final double minZ, final double maxZ) { + this.timestamp = System.currentTimeMillis(); + if (minX < maxX) { + this.minX = minX; + this.maxX = maxX; + } + else { + this.minX = maxX; + this.maxX = minX; + } + if (minY < maxY) { + this.minY = minY; + this.maxY = maxY; + } + else { + this.minY = maxY; + this.maxY = minY; + } + if (minZ < maxZ) { + this.minZ = minZ; + this.maxZ = maxZ; + } + else { + this.minZ = maxZ; + this.maxZ = minZ; + } + } + + public double distance(final Location location) { + return Math.sqrt(Math.min(Math.pow(location.getX() - this.minX, 2.0), Math.pow(location.getX() - this.maxX, 2.0)) + Math.min(Math.pow(location.getZ() - this.minZ, 2.0), Math.pow(location.getZ() - this.maxZ, 2.0))); + } + + public double distance(final double x, final double z) { + final double dx = Math.min(Math.pow(x - this.minX, 2.0), Math.pow(x - this.maxX, 2.0)); + final double dz = Math.min(Math.pow(z - this.minZ, 2.0), Math.pow(z - this.maxZ, 2.0)); + return Math.sqrt(dx + dz); + } + + public double distance(final BoundingBox box) { + final double dx = Math.min(Math.pow(box.minX - this.minX, 2.0), Math.pow(box.maxX - this.maxX, 2.0)); + final double dz = Math.min(Math.pow(box.minZ - this.minZ, 2.0), Math.pow(box.maxZ - this.maxZ, 2.0)); + return Math.sqrt(dx + dz); + } + + public BoundingBox add(final BoundingBox box) { + this.minX += box.minX; + this.minY += box.minY; + this.minZ += box.minZ; + this.maxX += box.maxX; + this.maxY += box.maxY; + this.maxZ += box.maxZ; + return this; + } + + public BoundingBox move(final double x, final double y, final double z) { + this.minX += x; + this.minY += y; + this.minZ += z; + this.maxX += x; + this.maxY += y; + this.maxZ += z; + return this; + } + + public BoundingBox expand(final double x, final double y, final double z) { + this.minX -= x; + this.minY -= y; + this.minZ -= z; + this.maxX += x; + this.maxY += y; + this.maxZ += z; + return this; + } + + public boolean checkAllBlocks(final World world, final Predicate predicate) { + final int first = (int)Math.floor(this.minX); + final int second = (int)Math.ceil(this.maxX); + final int third = (int)Math.floor(this.minY); + final int forth = (int)Math.ceil(this.maxY); + final int fifth = (int)Math.floor(this.minZ); + final int sixth = (int)Math.ceil(this.maxZ); + final List list = new LinkedList(); + list.add(BlockUtil.getBlockTypeASync(world, first, third, fifth)); + for (int i = first; i < second; ++i) { + for (int j = third; j < forth; ++j) { + for (int k = fifth; k < sixth; ++k) { + list.add(BlockUtil.getBlockTypeASync(world, i, j, k)); + } + } + } + return StreamUtil.allMatch(list, predicate); + } + + public double middleX() { + return (this.minX + this.maxX) / 2.0; + } + + public double middleY() { + return (this.minY + this.maxY) / 2.0; + } + + public double middleZ() { + return (this.minZ + this.maxZ) / 2.0; + } + + private boolean isVecInYZ(final Point vec) { + return vec != null && vec.getY() >= this.minY && vec.getY() <= this.maxY && vec.getZ() >= this.minZ && vec.getZ() <= this.maxZ; + } + + private boolean isVecInXZ(final Point vec) { + return vec != null && vec.getX() >= this.minX && vec.getX() <= this.maxX && vec.getZ() >= this.minZ && vec.getZ() <= this.maxZ; + } + + private boolean isVecInXY(final Point vec) { + return vec != null && vec.getX() >= this.minX && vec.getX() <= this.maxX && vec.getY() >= this.minY && vec.getY() <= this.maxY; + } + + public MovingPoint calculateIntercept(final Point vecA, final Point vecB) { + Point vec3 = vecA.getIntermediateWithXValue(vecB, this.minX); + Point vec4 = vecA.getIntermediateWithXValue(vecB, this.maxX); + Point vec5 = vecA.getIntermediateWithYValue(vecB, this.minY); + Point vec6 = vecA.getIntermediateWithYValue(vecB, this.maxY); + Point vec7 = vecA.getIntermediateWithZValue(vecB, this.minZ); + Point vec8 = vecA.getIntermediateWithZValue(vecB, this.maxZ); + if (!this.isVecInYZ(vec3)) { + vec3 = null; + } + if (!this.isVecInYZ(vec4)) { + vec4 = null; + } + if (!this.isVecInXZ(vec5)) { + vec5 = null; + } + if (!this.isVecInXZ(vec6)) { + vec6 = null; + } + if (!this.isVecInXY(vec7)) { + vec7 = null; + } + if (!this.isVecInXY(vec8)) { + vec8 = null; + } + Point vec9 = null; + if (vec3 != null) { + vec9 = vec3; + } + if (vec4 != null && (vec9 == null || vecA.squareDistanceTo(vec4) < vecA.squareDistanceTo(vec9))) { + vec9 = vec4; + } + if (vec5 != null && (vec9 == null || vecA.squareDistanceTo(vec5) < vecA.squareDistanceTo(vec9))) { + vec9 = vec5; + } + if (vec6 != null && (vec9 == null || vecA.squareDistanceTo(vec6) < vecA.squareDistanceTo(vec9))) { + vec9 = vec6; + } + if (vec7 != null && (vec9 == null || vecA.squareDistanceTo(vec7) < vecA.squareDistanceTo(vec9))) { + vec9 = vec7; + } + if (vec8 != null && (vec9 == null || vecA.squareDistanceTo(vec8) < vecA.squareDistanceTo(vec9))) { + vec9 = vec8; + } + if (vec9 == null) { + return null; + } + EnumFacing enumfacing = null; + if (vec9 == vec3) { + enumfacing = EnumFacing.WEST; + } + else if (vec9 == vec4) { + enumfacing = EnumFacing.EAST; + } + else if (vec9 == vec5) { + enumfacing = EnumFacing.DOWN; + } + else if (vec9 == vec6) { + enumfacing = EnumFacing.UP; + } + else if (vec9 == vec7) { + enumfacing = EnumFacing.NORTH; + } + else { + enumfacing = EnumFacing.SOUTH; + } + return new MovingPoint(vec9, enumfacing); + } + + public BoundingBox cloneBB() { + return new BoundingBox(this.minX, this.maxX, this.minY, this.maxY, this.minZ, this.maxZ); + } + + public double getMinX() { + return this.minX; + } + + public double getMinY() { + return this.minY; + } + + public double getMinZ() { + return this.minZ; + } + + public double getMaxX() { + return this.maxX; + } + + public double getMaxY() { + return this.maxY; + } + + public double getMaxZ() { + return this.maxZ; + } + + public long getTimestamp() { + return this.timestamp; + } + + public void setMinX(final double minX) { + this.minX = minX; + } + + public void setMinY(final double minY) { + this.minY = minY; + } + + public void setMinZ(final double minZ) { + this.minZ = minZ; + } + + public void setMaxX(final double maxX) { + this.maxX = maxX; + } + + public void setMaxY(final double maxY) { + this.maxY = maxY; + } + + public void setMaxZ(final double maxZ) { + this.maxZ = maxZ; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/discord/DiscordWebhook.java b/src/main/java/me/frep/vulcan/spigot/util/discord/DiscordWebhook.java new file mode 100644 index 0000000..410d6bf --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/discord/DiscordWebhook.java @@ -0,0 +1,372 @@ +package me.frep.vulcan.spigot.util.discord; + +import java.util.Set; +import java.lang.reflect.Array; +import java.util.Map; +import java.util.HashMap; +import java.io.IOException; +import java.io.OutputStream; +import java.awt.Color; +import java.util.Iterator; +import javax.net.ssl.HttpsURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +public class DiscordWebhook +{ + private final String url; + private String content; + private String username; + private String avatarUrl; + private boolean tts; + private List embeds; + + public DiscordWebhook(final String url) { + this.embeds = new ArrayList(); + this.url = url; + } + + public void setContent(final String content) { + this.content = content; + } + + public void setUsername(final String username) { + this.username = username; + } + + public void setAvatarUrl(final String avatarUrl) { + this.avatarUrl = avatarUrl; + } + + public void setTts(final boolean tts) { + this.tts = tts; + } + + public void addEmbed(final EmbedObject embed) { + this.embeds.add(embed); + } + + public void execute() throws IOException { + if (this.content == null && this.embeds.isEmpty()) { + throw new IllegalArgumentException("Set content or add at least one EmbedObject"); + } + final JSONObject json = new JSONObject(); + json.put("content", this.content); + json.put("username", this.username); + json.put("avatar_url", this.avatarUrl); + json.put("tts", this.tts); + if (!this.embeds.isEmpty()) { + final List embedObjects = new ArrayList(); + for (final EmbedObject embed : this.embeds) { + final JSONObject jsonEmbed = new JSONObject(); + jsonEmbed.put("title", embed.getTitle()); + jsonEmbed.put("description", embed.getDescription()); + jsonEmbed.put("url", embed.getUrl()); + if (embed.getColor() != null) { + final Color color = embed.getColor(); + int rgb = color.getRed(); + rgb = (rgb << 8) + color.getGreen(); + rgb = (rgb << 8) + color.getBlue(); + jsonEmbed.put("color", rgb); + } + final EmbedObject.Footer footer = embed.getFooter(); + final EmbedObject.Image image = embed.getImage(); + final EmbedObject.Thumbnail thumbnail = embed.getThumbnail(); + final EmbedObject.Author author = embed.getAuthor(); + final List fields = embed.getFields(); + if (footer != null) { + final JSONObject jsonFooter = new JSONObject(); + jsonFooter.put("text", footer.getText()); + jsonFooter.put("icon_url", footer.getIconUrl()); + jsonEmbed.put("footer", jsonFooter); + } + if (image != null) { + final JSONObject jsonImage = new JSONObject(); + jsonImage.put("url", image.getUrl()); + jsonEmbed.put("image", jsonImage); + } + if (thumbnail != null) { + final JSONObject jsonThumbnail = new JSONObject(); + jsonThumbnail.put("url", thumbnail.getUrl()); + jsonEmbed.put("thumbnail", jsonThumbnail); + } + if (author != null) { + final JSONObject jsonAuthor = new JSONObject(); + jsonAuthor.put("name", author.getName()); + jsonAuthor.put("url", author.getUrl()); + jsonAuthor.put("icon_url", author.getIconUrl()); + jsonEmbed.put("author", jsonAuthor); + } + final List jsonFields = new ArrayList(); + for (final EmbedObject.Field field : fields) { + final JSONObject jsonField = new JSONObject(); + jsonField.put("name", field.getName()); + jsonField.put("value", field.getValue()); + jsonField.put("inline", field.isInline()); + jsonFields.add(jsonField); + } + jsonEmbed.put("fields", jsonFields.toArray()); + embedObjects.add(jsonEmbed); + } + json.put("embeds", embedObjects.toArray()); + } + final URL url = new URL(this.url); + final HttpsURLConnection connection = (HttpsURLConnection)url.openConnection(); + connection.addRequestProperty("Content-Type", "application/json"); + connection.addRequestProperty("User-Agent", "VulcanWebhook"); + connection.setDoOutput(true); + connection.setRequestMethod("POST"); + final OutputStream stream = connection.getOutputStream(); + stream.write(json.toString().getBytes()); + stream.flush(); + stream.close(); + connection.getInputStream().close(); + connection.disconnect(); + } + + public static class EmbedObject + { + private String title; + private String description; + private String url; + private Color color; + private Footer footer; + private Thumbnail thumbnail; + private Image image; + private Author author; + private List fields; + + public EmbedObject() { + this.fields = new ArrayList(); + } + + public String getTitle() { + return this.title; + } + + public String getDescription() { + return this.description; + } + + public String getUrl() { + return this.url; + } + + public Color getColor() { + return this.color; + } + + public Footer getFooter() { + return this.footer; + } + + public Thumbnail getThumbnail() { + return this.thumbnail; + } + + public Image getImage() { + return this.image; + } + + public Author getAuthor() { + return this.author; + } + + public List getFields() { + return this.fields; + } + + public EmbedObject setTitle(final String title) { + this.title = title; + return this; + } + + public EmbedObject setDescription(final String description) { + this.description = description; + return this; + } + + public EmbedObject setUrl(final String url) { + this.url = url; + return this; + } + + public EmbedObject setColor(final Color color) { + this.color = color; + return this; + } + + public EmbedObject setFooter(final String text, final String icon) { + this.footer = new Footer(text, icon); + return this; + } + + public EmbedObject setThumbnail(final String url) { + this.thumbnail = new Thumbnail(url); + return this; + } + + public EmbedObject setImage(final String url) { + this.image = new Image(url); + return this; + } + + public EmbedObject setAuthor(final String name, final String url, final String icon) { + this.author = new Author(name, url, icon); + return this; + } + + public EmbedObject addField(final String name, final String value, final boolean inline) { + this.fields.add(new Field(name, value, inline)); + return this; + } + + private class Footer + { + private String text; + private String iconUrl; + + private Footer(final String text, final String iconUrl) { + this.text = text; + this.iconUrl = iconUrl; + } + + private String getText() { + return this.text; + } + + private String getIconUrl() { + return this.iconUrl; + } + } + + private class Thumbnail + { + private String url; + + private Thumbnail(final String url) { + this.url = url; + } + + private String getUrl() { + return this.url; + } + } + + private class Image + { + private String url; + + private Image(final String url) { + this.url = url; + } + + private String getUrl() { + return this.url; + } + } + + private class Author + { + private String name; + private String url; + private String iconUrl; + + private Author(final String name, final String url, final String iconUrl) { + this.name = name; + this.url = url; + this.iconUrl = iconUrl; + } + + private String getName() { + return this.name; + } + + private String getUrl() { + return this.url; + } + + private String getIconUrl() { + return this.iconUrl; + } + } + + private class Field + { + private String name; + private String value; + private boolean inline; + + private Field(final String name, final String value, final boolean inline) { + this.name = name; + this.value = value; + this.inline = inline; + } + + private String getName() { + return this.name; + } + + private String getValue() { + return this.value; + } + + private boolean isInline() { + return this.inline; + } + } + } + + private class JSONObject + { + private final HashMap map; + + private JSONObject() { + this.map = new HashMap(); + } + + void put(final String key, final Object value) { + if (value != null) { + this.map.put(key, value); + } + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + final Set> entrySet = this.map.entrySet(); + builder.append("{"); + int i = 0; + for (final Map.Entry entry : entrySet) { + final Object val = entry.getValue(); + builder.append(this.quote(entry.getKey())).append(":"); + if (val instanceof String) { + builder.append(this.quote(String.valueOf(val))); + } + else if (val instanceof Integer) { + builder.append(Integer.valueOf(String.valueOf(val))); + } + else if (val instanceof Boolean) { + builder.append(val); + } + else if (val instanceof JSONObject) { + builder.append(val.toString()); + } + else if (val.getClass().isArray()) { + builder.append("["); + for (int len = Array.getLength(val), j = 0; j < len; ++j) { + builder.append(Array.get(val, j).toString()).append((j != len - 1) ? "," : ""); + } + builder.append("]"); + } + builder.append((++i == entrySet.size()) ? "}" : ","); + } + return builder.toString(); + } + + private String quote(final String string) { + return "\"" + string + "\""; + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/material/XMaterial.java b/src/main/java/me/frep/vulcan/spigot/util/material/XMaterial.java new file mode 100644 index 0000000..efc7536 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/material/XMaterial.java @@ -0,0 +1,1486 @@ +package me.frep.vulcan.spigot.util.material; + +import org.bukkit.Bukkit; +import java.util.List; +import java.util.HashSet; +import java.util.Arrays; +import java.util.regex.PatternSyntaxException; +import com.google.common.cache.CacheLoader; +import java.util.concurrent.TimeUnit; +import com.google.common.cache.CacheBuilder; +import java.util.HashMap; +import org.jetbrains.annotations.NotNull; +import org.apache.commons.lang.WordUtils; +import java.util.Iterator; +import java.util.Locale; +import java.util.Collection; +import org.bukkit.inventory.ItemStack; +import java.util.Objects; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.Validate; +import java.util.Optional; +import javax.annotation.Nullable; +import org.bukkit.Material; +import javax.annotation.Nonnull; +import java.util.Set; +import java.util.regex.Pattern; +import com.google.common.cache.LoadingCache; +import com.google.common.cache.Cache; +import java.util.Map; + +public enum XMaterial +{ + ACACIA_BOAT(new String[] { "BOAT_ACACIA" }), + ACACIA_BUTTON(new String[] { "WOOD_BUTTON" }), + ACACIA_DOOR(new String[] { "ACACIA_DOOR", "ACACIA_DOOR_ITEM" }), + ACACIA_FENCE, + ACACIA_FENCE_GATE, + ACACIA_LEAVES(new String[] { "LEAVES_2" }), + ACACIA_LOG(new String[] { "LOG_2" }), + ACACIA_PLANKS(4, new String[] { "WOOD" }), + ACACIA_PRESSURE_PLATE(new String[] { "WOOD_PLATE" }), + ACACIA_SAPLING(4, new String[] { "SAPLING" }), + ACACIA_SIGN(new String[] { "SIGN_POST", "SIGN" }), + ACACIA_SLAB(4, new String[] { "WOOD_DOUBLE_STEP", "WOOD_STEP", "WOODEN_SLAB" }), + ACACIA_STAIRS, + ACACIA_TRAPDOOR(new String[] { "TRAP_DOOR" }), + ACACIA_WALL_SIGN(new String[] { "WALL_SIGN" }), + ACACIA_WOOD(new String[] { "LOG_2" }), + ACTIVATOR_RAIL, + AIR, + ALLIUM(2, new String[] { "RED_ROSE" }), + ANCIENT_DEBRIS(16), + ANDESITE(5, new String[] { "STONE" }), + ANDESITE_SLAB, + ANDESITE_STAIRS, + ANDESITE_WALL, + ANVIL, + APPLE, + ARMOR_STAND, + ARROW, + ATTACHED_MELON_STEM(7, new String[] { "MELON_STEM" }), + ATTACHED_PUMPKIN_STEM(7, new String[] { "PUMPKIN_STEM" }), + AZURE_BLUET(3, new String[] { "RED_ROSE" }), + BAKED_POTATO, + BAMBOO(0, 14, new String[0]), + BAMBOO_SAPLING(14), + BARREL(0, 14, new String[0]), + BARRIER, + BASALT(16), + BAT_SPAWN_EGG(65, new String[] { "MONSTER_EGG" }), + BEACON, + BEDROCK, + BEEF(new String[] { "RAW_BEEF" }), + BEEHIVE(15), + BEETROOT(new String[] { "BEETROOT_BLOCK" }), + BEETROOTS(new String[] { "BEETROOT" }), + BEETROOT_SEEDS, + BEETROOT_SOUP, + BEE_NEST(15), + BEE_SPAWN_EGG(15), + BELL(14), + BIRCH_BOAT(new String[] { "BOAT_BIRCH" }), + BIRCH_BUTTON(new String[] { "WOOD_BUTTON" }), + BIRCH_DOOR(new String[] { "BIRCH_DOOR", "BIRCH_DOOR_ITEM" }), + BIRCH_FENCE, + BIRCH_FENCE_GATE, + BIRCH_LEAVES(2, new String[] { "LEAVES" }), + BIRCH_LOG(2, new String[] { "LOG" }), + BIRCH_PLANKS(2, new String[] { "WOOD" }), + BIRCH_PRESSURE_PLATE(new String[] { "WOOD_PLATE" }), + BIRCH_SAPLING(2, new String[] { "SAPLING" }), + BIRCH_SIGN(new String[] { "SIGN_POST", "SIGN" }), + BIRCH_SLAB(2, new String[] { "WOOD_DOUBLE_STEP", "WOOD_STEP", "WOODEN_SLAB" }), + BIRCH_STAIRS(new String[] { "BIRCH_WOOD_STAIRS" }), + BIRCH_TRAPDOOR(new String[] { "TRAP_DOOR" }), + BIRCH_WALL_SIGN(new String[] { "WALL_SIGN" }), + BIRCH_WOOD(2, new String[] { "LOG" }), + BLACKSTONE(16), + BLACKSTONE_SLAB(16), + BLACKSTONE_STAIRS(16), + BLACKSTONE_WALL(16), + BLACK_BANNER(new String[] { "STANDING_BANNER", "BANNER" }), + BLACK_BED(15, new String[] { "BED_BLOCK", "BED" }), + BLACK_CARPET(15, new String[] { "CARPET" }), + BLACK_CONCRETE(15, new String[] { "CONCRETE" }), + BLACK_CONCRETE_POWDER(15, new String[] { "CONCRETE_POWDER" }), + BLACK_DYE(0, 14, new String[] { "INK_SACK", "INK_SAC" }), + BLACK_GLAZED_TERRACOTTA(15, 12, new String[0]), + BLACK_SHULKER_BOX, + BLACK_STAINED_GLASS(15, new String[] { "STAINED_GLASS" }), + BLACK_STAINED_GLASS_PANE(15, new String[] { "STAINED_GLASS_PANE" }), + BLACK_TERRACOTTA(15, new String[] { "STAINED_CLAY" }), + BLACK_WALL_BANNER(new String[] { "WALL_BANNER" }), + BLACK_WOOL(15, new String[] { "WOOL" }), + BLAST_FURNACE(0, 14, new String[0]), + BLAZE_POWDER, + BLAZE_ROD, + BLAZE_SPAWN_EGG(61, new String[] { "MONSTER_EGG" }), + BLUE_BANNER(4, new String[] { "STANDING_BANNER", "BANNER" }), + BLUE_BED(11, new String[] { "BED_BLOCK", "BED" }), + BLUE_CARPET(11, new String[] { "CARPET" }), + BLUE_CONCRETE(11, new String[] { "CONCRETE" }), + BLUE_CONCRETE_POWDER(11, new String[] { "CONCRETE_POWDER" }), + BLUE_DYE(4, new String[] { "INK_SACK", "LAPIS_LAZULI" }), + BLUE_GLAZED_TERRACOTTA(11, 12, new String[0]), + BLUE_ICE(0, 13, new String[0]), + BLUE_ORCHID(1, new String[] { "RED_ROSE" }), + BLUE_SHULKER_BOX, + BLUE_STAINED_GLASS(11, new String[] { "STAINED_GLASS" }), + BLUE_STAINED_GLASS_PANE(11, new String[] { "THIN_GLASS", "STAINED_GLASS_PANE" }), + BLUE_TERRACOTTA(11, new String[] { "STAINED_CLAY" }), + BLUE_WALL_BANNER(4, new String[] { "WALL_BANNER" }), + BLUE_WOOL(11, new String[] { "WOOL" }), + BONE, + BONE_BLOCK, + BONE_MEAL(15, new String[] { "INK_SACK" }), + BOOK, + BOOKSHELF, + BOW, + BOWL, + BRAIN_CORAL(13), + BRAIN_CORAL_BLOCK(13), + BRAIN_CORAL_FAN(13), + BRAIN_CORAL_WALL_FAN, + BREAD, + BREWING_STAND(new String[] { "BREWING_STAND", "BREWING_STAND_ITEM" }), + BRICK(new String[] { "CLAY_BRICK" }), + BRICKS(new String[] { "BRICK" }), + BRICK_SLAB(4, new String[] { "STEP" }), + BRICK_STAIRS, + BRICK_WALL, + BROWN_BANNER(3, new String[] { "STANDING_BANNER", "BANNER" }), + BROWN_BED(12, new String[] { "BED_BLOCK", "BED" }), + BROWN_CARPET(12, new String[] { "CARPET" }), + BROWN_CONCRETE(12, new String[] { "CONCRETE" }), + BROWN_CONCRETE_POWDER(12, new String[] { "CONCRETE_POWDER" }), + BROWN_DYE(3, new String[] { "INK_SACK", "DYE", "COCOA_BEANS" }), + BROWN_GLAZED_TERRACOTTA(12, 12, new String[0]), + BROWN_MUSHROOM, + BROWN_MUSHROOM_BLOCK(new String[] { "BROWN_MUSHROOM", "HUGE_MUSHROOM_1" }), + BROWN_SHULKER_BOX, + BROWN_STAINED_GLASS(12, new String[] { "STAINED_GLASS" }), + BROWN_STAINED_GLASS_PANE(12, new String[] { "THIN_GLASS", "STAINED_GLASS_PANE" }), + BROWN_TERRACOTTA(12, new String[] { "STAINED_CLAY" }), + BROWN_WALL_BANNER(3, new String[] { "WALL_BANNER" }), + BROWN_WOOL(12, new String[] { "WOOL" }), + BUBBLE_COLUMN(13), + BUBBLE_CORAL(13), + BUBBLE_CORAL_BLOCK(13), + BUBBLE_CORAL_FAN(13), + BUBBLE_CORAL_WALL_FAN, + BUCKET, + CACTUS, + CAKE(new String[] { "CAKE_BLOCK" }), + CAMPFIRE(14), + CARROT(new String[] { "CARROT_ITEM" }), + CARROTS(new String[] { "CARROT" }), + CARROT_ON_A_STICK(new String[] { "CARROT_STICK" }), + CARTOGRAPHY_TABLE(0, 14, new String[0]), + CARVED_PUMPKIN(1, 13, new String[0]), + CAT_SPAWN_EGG, + CAULDRON(new String[] { "CAULDRON", "CAULDRON_ITEM" }), + CAVE_AIR(new String[] { "AIR" }), + CAVE_SPIDER_SPAWN_EGG(59, new String[] { "MONSTER_EGG" }), + CHAIN(16), + CHAINMAIL_BOOTS, + CHAINMAIL_CHESTPLATE, + CHAINMAIL_HELMET, + CHAINMAIL_LEGGINGS, + CHAIN_COMMAND_BLOCK(new String[] { "COMMAND", "COMMAND_CHAIN" }), + CHARCOAL(1, new String[] { "COAL" }), + CHEST(new String[] { "LOCKED_CHEST" }), + CHEST_MINECART(new String[] { "STORAGE_MINECART" }), + CHICKEN(new String[] { "RAW_CHICKEN" }), + CHICKEN_SPAWN_EGG(93, new String[] { "MONSTER_EGG" }), + CHIPPED_ANVIL(1, new String[] { "ANVIL" }), + CHISELED_NETHER_BRICKS(1, new String[] { "NETHER_BRICKS" }), + CHISELED_POLISHED_BLACKSTONE(0, 16, new String[] { "POLISHED_BLACKSTONE" }), + CHISELED_QUARTZ_BLOCK(1, new String[] { "QUARTZ_BLOCK" }), + CHISELED_RED_SANDSTONE(1, new String[] { "RED_SANDSTONE" }), + CHISELED_SANDSTONE(1, new String[] { "SANDSTONE" }), + CHISELED_STONE_BRICKS(3, new String[] { "SMOOTH_BRICK" }), + CHORUS_FLOWER(0, 9, new String[0]), + CHORUS_FRUIT(0, 9, new String[0]), + CHORUS_PLANT(0, 9, new String[0]), + CLAY(new String[] { "HARD_CLAY" }), + CLAY_BALL, + CLOCK(new String[] { "WATCH" }), + COAL, + COAL_BLOCK, + COAL_ORE, + COARSE_DIRT(1, new String[] { "DIRT" }), + COBBLESTONE, + COBBLESTONE_SLAB(3, new String[] { "STEP" }), + COBBLESTONE_STAIRS, + COBBLESTONE_WALL(new String[] { "COBBLE_WALL" }), + COBWEB(new String[] { "WEB" }), + COCOA(15), + COCOA_BEANS(3, new String[] { "INK_SACK" }), + COD(new String[] { "RAW_FISH" }), + COD_BUCKET(0, 13, new String[0]), + COD_SPAWN_EGG(0, 13, new String[0]), + COMMAND_BLOCK(new String[] { "COMMAND" }), + COMMAND_BLOCK_MINECART(new String[] { "COMMAND_MINECART" }), + COMPARATOR(new String[] { "REDSTONE_COMPARATOR_OFF", "REDSTONE_COMPARATOR_ON", "REDSTONE_COMPARATOR" }), + COMPASS, + COMPOSTER(0, 14, new String[0]), + CONDUIT(0, 13, new String[] { "BEACON" }), + COOKED_BEEF, + COOKED_CHICKEN, + COOKED_COD(new String[] { "COOKED_FISH" }), + COOKED_MUTTON, + COOKED_PORKCHOP(new String[] { "PORK", "GRILLED_PORK" }), + COOKED_RABBIT, + COOKED_SALMON(1, new String[] { "COOKED_FISH" }), + COOKIE, + CORNFLOWER(4, 14, new String[0]), + COW_SPAWN_EGG(92, new String[] { "MONSTER_EGG" }), + CRACKED_NETHER_BRICKS(2, new String[] { "NETHER_BRICKS" }), + CRACKED_POLISHED_BLACKSTONE_BRICKS(0, 16, new String[] { "POLISHED_BLACKSTONE_BRICKS" }), + CRACKED_STONE_BRICKS(2, new String[] { "SMOOTH_BRICK" }), + CRAFTING_TABLE(new String[] { "WORKBENCH" }), + CREEPER_BANNER_PATTERN, + CREEPER_HEAD(4, new String[] { "SKULL", "SKULL_ITEM" }), + CREEPER_SPAWN_EGG(50, new String[] { "MONSTER_EGG" }), + CREEPER_WALL_HEAD(4, new String[] { "SKULL", "SKULL_ITEM" }), + CRIMSON_BUTTON(16), + CRIMSON_DOOR(16), + CRIMSON_FENCE(16), + CRIMSON_FENCE_GATE(16), + CRIMSON_FUNGUS(16), + CRIMSON_HYPHAE(16), + CRIMSON_NYLIUM(16), + CRIMSON_PLANKS(16), + CRIMSON_PRESSURE_PLATE(16), + CRIMSON_ROOTS(16), + CRIMSON_SIGN(0, 16, new String[] { "SIGN_POST" }), + CRIMSON_SLAB(16), + CRIMSON_STAIRS(16), + CRIMSON_STEM(16), + CRIMSON_TRAPDOOR(16), + CRIMSON_WALL_SIGN(0, 16, new String[] { "WALL_SIGN" }), + CROSSBOW, + CRYING_OBSIDIAN(16), + CUT_RED_SANDSTONE(13), + CUT_RED_SANDSTONE_SLAB(new String[] { "STONE_SLAB2" }), + CUT_SANDSTONE(13), + CUT_SANDSTONE_SLAB(new String[] { "STEP" }), + CYAN_BANNER(6, new String[] { "STANDING_BANNER", "BANNER" }), + CYAN_BED(9, new String[] { "BED_BLOCK", "BED" }), + CYAN_CARPET(9, new String[] { "CARPET" }), + CYAN_CONCRETE(9, new String[] { "CONCRETE" }), + CYAN_CONCRETE_POWDER(9, new String[] { "CONCRETE_POWDER" }), + CYAN_DYE(6, new String[] { "INK_SACK" }), + CYAN_GLAZED_TERRACOTTA(9, 12, new String[0]), + CYAN_SHULKER_BOX, + CYAN_STAINED_GLASS(9, new String[] { "STAINED_GLASS" }), + CYAN_STAINED_GLASS_PANE(9, new String[] { "STAINED_GLASS_PANE" }), + CYAN_TERRACOTTA(9, new String[] { "STAINED_CLAY" }), + CYAN_WALL_BANNER(6, new String[] { "WALL_BANNER" }), + CYAN_WOOL(9, new String[] { "WOOL" }), + DAMAGED_ANVIL(2, new String[] { "ANVIL" }), + DANDELION(new String[] { "YELLOW_FLOWER" }), + DARK_OAK_BOAT(new String[] { "BOAT_DARK_OAK" }), + DARK_OAK_BUTTON(new String[] { "WOOD_BUTTON" }), + DARK_OAK_DOOR(new String[] { "DARK_OAK_DOOR", "DARK_OAK_DOOR_ITEM" }), + DARK_OAK_FENCE, + DARK_OAK_FENCE_GATE, + DARK_OAK_LEAVES(4, new String[] { "LEAVES", "LEAVES_2" }), + DARK_OAK_LOG(1, new String[] { "LOG", "LOG_2" }), + DARK_OAK_PLANKS(5, new String[] { "WOOD" }), + DARK_OAK_PRESSURE_PLATE(new String[] { "WOOD_PLATE" }), + DARK_OAK_SAPLING(5, new String[] { "SAPLING" }), + DARK_OAK_SIGN(new String[] { "SIGN_POST", "SIGN" }), + DARK_OAK_SLAB(5, new String[] { "WOOD_DOUBLE_STEP", "WOOD_STEP", "WOODEN_SLAB" }), + DARK_OAK_STAIRS, + DARK_OAK_TRAPDOOR(new String[] { "TRAP_DOOR" }), + DARK_OAK_WALL_SIGN(new String[] { "WALL_SIGN" }), + DARK_OAK_WOOD(1, new String[] { "LOG", "LOG_2" }), + DARK_PRISMARINE(1, new String[] { "PRISMARINE" }), + DARK_PRISMARINE_SLAB(13), + DARK_PRISMARINE_STAIRS(13), + DAYLIGHT_DETECTOR(new String[] { "DAYLIGHT_DETECTOR_INVERTED" }), + DEAD_BRAIN_CORAL(13), + DEAD_BRAIN_CORAL_BLOCK(13), + DEAD_BRAIN_CORAL_FAN(13), + DEAD_BRAIN_CORAL_WALL_FAN(13), + DEAD_BUBBLE_CORAL(13), + DEAD_BUBBLE_CORAL_BLOCK(13), + DEAD_BUBBLE_CORAL_FAN(13), + DEAD_BUBBLE_CORAL_WALL_FAN(13), + DEAD_BUSH, + DEAD_FIRE_CORAL(13), + DEAD_FIRE_CORAL_BLOCK(13), + DEAD_FIRE_CORAL_FAN(13), + DEAD_FIRE_CORAL_WALL_FAN(13), + DEAD_HORN_CORAL(13), + DEAD_HORN_CORAL_BLOCK(13), + DEAD_HORN_CORAL_FAN(13), + DEAD_HORN_CORAL_WALL_FAN(13), + DEAD_TUBE_CORAL(13), + DEAD_TUBE_CORAL_BLOCK(13), + DEAD_TUBE_CORAL_FAN(13), + DEAD_TUBE_CORAL_WALL_FAN(13), + DEBUG_STICK(0, 13, new String[0]), + DETECTOR_RAIL, + DIAMOND, + DIAMOND_AXE, + DIAMOND_BLOCK, + DIAMOND_BOOTS, + DIAMOND_CHESTPLATE, + DIAMOND_HELMET, + DIAMOND_HOE, + DIAMOND_HORSE_ARMOR(new String[] { "DIAMOND_BARDING" }), + DIAMOND_LEGGINGS, + DIAMOND_ORE, + DIAMOND_PICKAXE, + DIAMOND_SHOVEL(new String[] { "DIAMOND_SPADE" }), + DIAMOND_SWORD, + DIORITE(3, new String[] { "STONE" }), + DIORITE_SLAB, + DIORITE_STAIRS, + DIORITE_WALL, + DIRT, + DISPENSER, + DOLPHIN_SPAWN_EGG(0, 13, new String[0]), + DONKEY_SPAWN_EGG(32, new String[] { "MONSTER_EGG" }), + DRAGON_BREATH(new String[] { "DRAGONS_BREATH" }), + DRAGON_EGG, + DRAGON_HEAD(5, 9, new String[] { "SKULL", "SKULL_ITEM" }), + DRAGON_WALL_HEAD(5, new String[] { "SKULL", "SKULL_ITEM" }), + DRIED_KELP(13), + DRIED_KELP_BLOCK(13), + DROPPER, + DROWNED_SPAWN_EGG(0, 13, new String[0]), + EGG, + ELDER_GUARDIAN_SPAWN_EGG(4, new String[] { "MONSTER_EGG" }), + ELYTRA, + EMERALD, + EMERALD_BLOCK, + EMERALD_ORE, + ENCHANTED_BOOK, + ENCHANTED_GOLDEN_APPLE(1, new String[] { "GOLDEN_APPLE" }), + ENCHANTING_TABLE(new String[] { "ENCHANTMENT_TABLE" }), + ENDERMAN_SPAWN_EGG(58, new String[] { "MONSTER_EGG" }), + ENDERMITE_SPAWN_EGG(67, new String[] { "MONSTER_EGG" }), + ENDER_CHEST, + ENDER_EYE(new String[] { "EYE_OF_ENDER" }), + ENDER_PEARL, + END_CRYSTAL, + END_GATEWAY(0, 9, new String[0]), + END_PORTAL(new String[] { "ENDER_PORTAL" }), + END_PORTAL_FRAME(new String[] { "ENDER_PORTAL_FRAME" }), + END_ROD(0, 9, new String[0]), + END_STONE(new String[] { "ENDER_STONE" }), + END_STONE_BRICKS(new String[] { "END_BRICKS" }), + END_STONE_BRICK_SLAB(6, new String[] { "STEP" }), + END_STONE_BRICK_STAIRS(new String[] { "SMOOTH_STAIRS" }), + END_STONE_BRICK_WALL, + EVOKER_SPAWN_EGG(34, new String[] { "MONSTER_EGG" }), + EXPERIENCE_BOTTLE(new String[] { "EXP_BOTTLE" }), + FARMLAND(new String[] { "SOIL" }), + FEATHER, + FERMENTED_SPIDER_EYE, + FERN(2, new String[] { "LONG_GRASS" }), + FILLED_MAP(new String[] { "MAP" }), + FIRE, + FIREWORK_ROCKET(new String[] { "FIREWORK" }), + FIREWORK_STAR(new String[] { "FIREWORK_CHARGE" }), + FIRE_CHARGE(new String[] { "FIREBALL" }), + FIRE_CORAL(13), + FIRE_CORAL_BLOCK(13), + FIRE_CORAL_FAN(13), + FIRE_CORAL_WALL_FAN, + FISHING_ROD, + FLETCHING_TABLE(0, 14, new String[0]), + FLINT, + FLINT_AND_STEEL, + FLOWER_BANNER_PATTERN, + FLOWER_POT(new String[] { "FLOWER_POT", "FLOWER_POT_ITEM" }), + FOX_SPAWN_EGG(14), + FROSTED_ICE(0, 9, new String[0]), + FURNACE(new String[] { "BURNING_FURNACE" }), + FURNACE_MINECART(new String[] { "POWERED_MINECART" }), + GHAST_SPAWN_EGG(56, new String[] { "MONSTER_EGG" }), + GHAST_TEAR, + GILDED_BLACKSTONE(16), + GLASS, + GLASS_BOTTLE, + GLASS_PANE(new String[] { "THIN_GLASS" }), + GLISTERING_MELON_SLICE(new String[] { "SPECKLED_MELON" }), + GLOBE_BANNER_PATTERN, + GLOWSTONE, + GLOWSTONE_DUST, + GOLDEN_APPLE, + GOLDEN_AXE(new String[] { "GOLD_AXE" }), + GOLDEN_BOOTS(new String[] { "GOLD_BOOTS" }), + GOLDEN_CARROT, + GOLDEN_CHESTPLATE(new String[] { "GOLD_CHESTPLATE" }), + GOLDEN_HELMET(new String[] { "GOLD_HELMET" }), + GOLDEN_HOE(new String[] { "GOLD_HOE" }), + GOLDEN_HORSE_ARMOR(new String[] { "GOLD_BARDING" }), + GOLDEN_LEGGINGS(new String[] { "GOLD_LEGGINGS" }), + GOLDEN_PICKAXE(new String[] { "GOLD_PICKAXE" }), + GOLDEN_SHOVEL(new String[] { "GOLD_SPADE" }), + GOLDEN_SWORD(new String[] { "GOLD_SWORD" }), + GOLD_BLOCK, + GOLD_INGOT, + GOLD_NUGGET, + GOLD_ORE, + GRANITE(1, new String[] { "STONE" }), + GRANITE_SLAB, + GRANITE_STAIRS, + GRANITE_WALL, + GRASS(1, new String[] { "LONG_GRASS" }), + GRASS_BLOCK(new String[] { "GRASS" }), + GRASS_PATH, + GRAVEL, + GRAY_BANNER(8, new String[] { "STANDING_BANNER", "BANNER" }), + GRAY_BED(7, new String[] { "BED_BLOCK", "BED" }), + GRAY_CARPET(7, new String[] { "CARPET" }), + GRAY_CONCRETE(7, new String[] { "CONCRETE" }), + GRAY_CONCRETE_POWDER(7, new String[] { "CONCRETE_POWDER" }), + GRAY_DYE(8, new String[] { "INK_SACK" }), + GRAY_GLAZED_TERRACOTTA(7, 12, new String[0]), + GRAY_SHULKER_BOX, + GRAY_STAINED_GLASS(7, new String[] { "STAINED_GLASS" }), + GRAY_STAINED_GLASS_PANE(7, new String[] { "THIN_GLASS", "STAINED_GLASS_PANE" }), + GRAY_TERRACOTTA(7, new String[] { "STAINED_CLAY" }), + GRAY_WALL_BANNER(8, new String[] { "WALL_BANNER" }), + GRAY_WOOL(7, new String[] { "WOOL" }), + GREEN_BANNER(2, new String[] { "STANDING_BANNER", "BANNER" }), + GREEN_BED(13, new String[] { "BED_BLOCK", "BED" }), + GREEN_CARPET(13, new String[] { "CARPET" }), + GREEN_CONCRETE(13, new String[] { "CONCRETE" }), + GREEN_CONCRETE_POWDER(13, new String[] { "CONCRETE_POWDER" }), + GREEN_DYE(2, new String[] { "INK_SACK", "CACTUS_GREEN" }), + GREEN_GLAZED_TERRACOTTA(13, 12, new String[0]), + GREEN_SHULKER_BOX, + GREEN_STAINED_GLASS(13, new String[] { "STAINED_GLASS" }), + GREEN_STAINED_GLASS_PANE(13, new String[] { "THIN_GLASS", "STAINED_GLASS_PANE" }), + GREEN_TERRACOTTA(13, new String[] { "STAINED_CLAY" }), + GREEN_WALL_BANNER(2, new String[] { "WALL_BANNER" }), + GREEN_WOOL(13, new String[] { "WOOL" }), + GRINDSTONE(0, 14, new String[0]), + GUARDIAN_SPAWN_EGG(68, new String[] { "MONSTER_EGG" }), + GUNPOWDER(new String[] { "SULPHUR" }), + HAY_BLOCK, + HEART_OF_THE_SEA(13), + HEAVY_WEIGHTED_PRESSURE_PLATE(new String[] { "IRON_PLATE" }), + HOGLIN_SPAWN_EGG(0, 16, new String[] { "MONSTER_EGG" }), + HONEYCOMB(15), + HONEYCOMB_BLOCK(15), + HONEY_BLOCK(0, 15, new String[0]), + HONEY_BOTTLE(0, 15, new String[0]), + HOPPER, + HOPPER_MINECART, + HORN_CORAL(13), + HORN_CORAL_BLOCK(13), + HORN_CORAL_FAN(13), + HORN_CORAL_WALL_FAN, + HORSE_SPAWN_EGG(100, new String[] { "MONSTER_EGG" }), + HUSK_SPAWN_EGG(23, new String[] { "MONSTER_EGG" }), + ICE, + INFESTED_CHISELED_STONE_BRICKS(5, new String[] { "MONSTER_EGGS", "SMOOTH_BRICK" }), + INFESTED_COBBLESTONE(1, new String[] { "MONSTER_EGGS" }), + INFESTED_CRACKED_STONE_BRICKS(4, new String[] { "MONSTER_EGGS", "SMOOTH_BRICK" }), + INFESTED_MOSSY_STONE_BRICKS(3, new String[] { "MONSTER_EGGS" }), + INFESTED_STONE(new String[] { "MONSTER_EGGS" }), + INFESTED_STONE_BRICKS(2, new String[] { "MONSTER_EGGS", "SMOOTH_BRICK" }), + INK_SAC(new String[] { "INK_SACK" }), + IRON_AXE, + IRON_BARS(new String[] { "IRON_FENCE" }), + IRON_BLOCK, + IRON_BOOTS, + IRON_CHESTPLATE, + IRON_DOOR(new String[] { "IRON_DOOR_BLOCK" }), + IRON_HELMET, + IRON_HOE, + IRON_HORSE_ARMOR(new String[] { "IRON_BARDING" }), + IRON_INGOT, + IRON_LEGGINGS, + IRON_NUGGET, + IRON_ORE, + IRON_PICKAXE, + IRON_SHOVEL(new String[] { "IRON_SPADE" }), + IRON_SWORD, + IRON_TRAPDOOR, + ITEM_FRAME, + JACK_O_LANTERN, + JIGSAW(0, 14, new String[0]), + JUKEBOX, + JUNGLE_BOAT(new String[] { "BOAT_JUNGLE" }), + JUNGLE_BUTTON(new String[] { "WOOD_BUTTON" }), + JUNGLE_DOOR(new String[] { "JUNGLE_DOOR", "JUNGLE_DOOR_ITEM" }), + JUNGLE_FENCE, + JUNGLE_FENCE_GATE, + JUNGLE_LEAVES(3, new String[] { "LEAVES" }), + JUNGLE_LOG(3, new String[] { "LOG" }), + JUNGLE_PLANKS(3, new String[] { "WOOD" }), + JUNGLE_PRESSURE_PLATE(new String[] { "WOOD_PLATE" }), + JUNGLE_SAPLING(3, new String[] { "SAPLING" }), + JUNGLE_SIGN(new String[] { "SIGN_POST", "SIGN" }), + JUNGLE_SLAB(3, new String[] { "WOOD_DOUBLE_STEP", "WOOD_STEP", "WOODEN_SLAB" }), + JUNGLE_STAIRS(new String[] { "JUNGLE_WOOD_STAIRS" }), + JUNGLE_TRAPDOOR(new String[] { "TRAP_DOOR" }), + JUNGLE_WALL_SIGN(new String[] { "WALL_SIGN" }), + JUNGLE_WOOD(3, new String[] { "LOG" }), + KELP(13), + KELP_PLANT(13), + KNOWLEDGE_BOOK(0, 12, new String[] { "BOOK" }), + LADDER, + LANTERN(0, 14, new String[0]), + LAPIS_BLOCK, + LAPIS_LAZULI(4, new String[] { "INK_SACK" }), + LAPIS_ORE, + LARGE_FERN(3, new String[] { "DOUBLE_PLANT" }), + LAVA(new String[] { "STATIONARY_LAVA" }), + LAVA_BUCKET, + LEAD(new String[] { "LEASH" }), + LEATHER, + LEATHER_BOOTS, + LEATHER_CHESTPLATE, + LEATHER_HELMET, + LEATHER_HORSE_ARMOR(0, 14, new String[] { "IRON_HORSE_ARMOR" }), + LEATHER_LEGGINGS, + LECTERN(0, 14, new String[0]), + LEVER, + LIGHT_BLUE_BANNER(12, new String[] { "STANDING_BANNER", "BANNER" }), + LIGHT_BLUE_BED(3, new String[] { "BED_BLOCK", "BED" }), + LIGHT_BLUE_CARPET(3, new String[] { "CARPET" }), + LIGHT_BLUE_CONCRETE(3, new String[] { "CONCRETE" }), + LIGHT_BLUE_CONCRETE_POWDER(3, new String[] { "CONCRETE_POWDER" }), + LIGHT_BLUE_DYE(12, new String[] { "INK_SACK" }), + LIGHT_BLUE_GLAZED_TERRACOTTA(3, 12, new String[0]), + LIGHT_BLUE_SHULKER_BOX, + LIGHT_BLUE_STAINED_GLASS(3, new String[] { "STAINED_GLASS" }), + LIGHT_BLUE_STAINED_GLASS_PANE(3, new String[] { "THIN_GLASS", "STAINED_GLASS_PANE" }), + LIGHT_BLUE_TERRACOTTA(3, new String[] { "STAINED_CLAY" }), + LIGHT_BLUE_WALL_BANNER(12, new String[] { "WALL_BANNER", "STANDING_BANNER", "BANNER" }), + LIGHT_BLUE_WOOL(3, new String[] { "WOOL" }), + LIGHT_GRAY_BANNER(7, new String[] { "STANDING_BANNER", "BANNER" }), + LIGHT_GRAY_BED(8, new String[] { "BED_BLOCK", "BED" }), + LIGHT_GRAY_CARPET(8, new String[] { "CARPET" }), + LIGHT_GRAY_CONCRETE(8, new String[] { "CONCRETE" }), + LIGHT_GRAY_CONCRETE_POWDER(8, new String[] { "CONCRETE_POWDER" }), + LIGHT_GRAY_DYE(7, new String[] { "INK_SACK" }), + LIGHT_GRAY_GLAZED_TERRACOTTA(0, 12, new String[] { "STAINED_CLAY", "LIGHT_GRAY_TERRACOTTA", "SILVER_GLAZED_TERRACOTTA" }), + LIGHT_GRAY_SHULKER_BOX(new String[] { "SILVER_SHULKER_BOX" }), + LIGHT_GRAY_STAINED_GLASS(8, new String[] { "STAINED_GLASS" }), + LIGHT_GRAY_STAINED_GLASS_PANE(8, new String[] { "THIN_GLASS", "STAINED_GLASS_PANE" }), + LIGHT_GRAY_TERRACOTTA(8, new String[] { "STAINED_CLAY" }), + LIGHT_GRAY_WALL_BANNER(7, new String[] { "WALL_BANNER" }), + LIGHT_GRAY_WOOL(8, new String[] { "WOOL" }), + LIGHT_WEIGHTED_PRESSURE_PLATE(new String[] { "GOLD_PLATE" }), + LILAC(1, new String[] { "DOUBLE_PLANT" }), + LILY_OF_THE_VALLEY(15, 14, new String[0]), + LILY_PAD(new String[] { "WATER_LILY" }), + LIME_BANNER(10, new String[] { "STANDING_BANNER", "BANNER" }), + LIME_BED(5, new String[] { "BED_BLOCK", "BED" }), + LIME_CARPET(5, new String[] { "CARPET" }), + LIME_CONCRETE(5, new String[] { "CONCRETE" }), + LIME_CONCRETE_POWDER(5, new String[] { "CONCRETE_POWDER" }), + LIME_DYE(10, new String[] { "INK_SACK" }), + LIME_GLAZED_TERRACOTTA(5, 12, new String[0]), + LIME_SHULKER_BOX, + LIME_STAINED_GLASS(5, new String[] { "STAINED_GLASS" }), + LIME_STAINED_GLASS_PANE(5, new String[] { "STAINED_GLASS_PANE" }), + LIME_TERRACOTTA(5, new String[] { "STAINED_CLAY" }), + LIME_WALL_BANNER(10, new String[] { "WALL_BANNER" }), + LIME_WOOL(5, new String[] { "WOOL" }), + LINGERING_POTION, + LLAMA_SPAWN_EGG(103, new String[] { "MONSTER_EGG" }), + LODESTONE(16), + LOOM(14), + MAGENTA_BANNER(13, new String[] { "STANDING_BANNER", "BANNER" }), + MAGENTA_BED(2, new String[] { "BED_BLOCK", "BED" }), + MAGENTA_CARPET(2, new String[] { "CARPET" }), + MAGENTA_CONCRETE(2, new String[] { "CONCRETE" }), + MAGENTA_CONCRETE_POWDER(2, new String[] { "CONCRETE_POWDER" }), + MAGENTA_DYE(13, new String[] { "INK_SACK" }), + MAGENTA_GLAZED_TERRACOTTA(2, 12, new String[0]), + MAGENTA_SHULKER_BOX, + MAGENTA_STAINED_GLASS(2, new String[] { "STAINED_GLASS" }), + MAGENTA_STAINED_GLASS_PANE(2, new String[] { "THIN_GLASS", "STAINED_GLASS_PANE" }), + MAGENTA_TERRACOTTA(2, new String[] { "STAINED_CLAY" }), + MAGENTA_WALL_BANNER(13, new String[] { "WALL_BANNER" }), + MAGENTA_WOOL(2, new String[] { "WOOL" }), + MAGMA_BLOCK(0, 10, new String[] { "MAGMA" }), + MAGMA_CREAM, + MAGMA_CUBE_SPAWN_EGG(62, new String[] { "MONSTER_EGG" }), + MAP(new String[] { "EMPTY_MAP" }), + MELON(new String[] { "MELON_BLOCK" }), + MELON_SEEDS, + MELON_SLICE(new String[] { "MELON" }), + MELON_STEM, + MILK_BUCKET, + MINECART, + MOJANG_BANNER_PATTERN, + MOOSHROOM_SPAWN_EGG(96, new String[] { "MONSTER_EGG" }), + MOSSY_COBBLESTONE, + MOSSY_COBBLESTONE_SLAB(3, new String[] { "STEP" }), + MOSSY_COBBLESTONE_STAIRS, + MOSSY_COBBLESTONE_WALL(1, new String[] { "COBBLE_WALL", "COBBLESTONE_WALL" }), + MOSSY_STONE_BRICKS(1, new String[] { "SMOOTH_BRICK" }), + MOSSY_STONE_BRICK_SLAB(5, new String[] { "STEP" }), + MOSSY_STONE_BRICK_STAIRS(new String[] { "SMOOTH_STAIRS" }), + MOSSY_STONE_BRICK_WALL, + MOVING_PISTON(new String[] { "PISTON_BASE", "PISTON_MOVING_PIECE" }), + MULE_SPAWN_EGG(32, new String[] { "MONSTER_EGG" }), + MUSHROOM_STEM(new String[] { "BROWN_MUSHROOM" }), + MUSHROOM_STEW(new String[] { "MUSHROOM_SOUP" }), + MUSIC_DISC_11(new String[] { "GOLD_RECORD" }), + MUSIC_DISC_13(new String[] { "GREEN_RECORD" }), + MUSIC_DISC_BLOCKS(new String[] { "RECORD_3" }), + MUSIC_DISC_CAT(new String[] { "RECORD_4" }), + MUSIC_DISC_CHIRP(new String[] { "RECORD_5" }), + MUSIC_DISC_FAR(new String[] { "RECORD_6" }), + MUSIC_DISC_MALL(new String[] { "RECORD_7" }), + MUSIC_DISC_MELLOHI(new String[] { "RECORD_8" }), + MUSIC_DISC_PIGSTEP(16), + MUSIC_DISC_STAL(new String[] { "RECORD_9" }), + MUSIC_DISC_STRAD(new String[] { "RECORD_10" }), + MUSIC_DISC_WAIT(new String[] { "RECORD_11" }), + MUSIC_DISC_WARD(new String[] { "RECORD_12" }), + MUTTON, + MYCELIUM(new String[] { "MYCEL" }), + NAME_TAG, + NAUTILUS_SHELL(13), + NETHERITE_AXE(16), + NETHERITE_BLOCK(16), + NETHERITE_BOOTS(16), + NETHERITE_CHESTPLATE(16), + NETHERITE_HELMET(16), + NETHERITE_HOE(16), + NETHERITE_INGOT(16), + NETHERITE_LEGGINGS(16), + NETHERITE_PICKAXE(16), + NETHERITE_SCRAP(16), + NETHERITE_SHOVEL(16), + NETHERITE_SWORD(16), + NETHERRACK, + NETHER_BRICK(new String[] { "NETHER_BRICK_ITEM" }), + NETHER_BRICKS(new String[] { "NETHER_BRICK" }), + NETHER_BRICK_FENCE(new String[] { "NETHER_FENCE" }), + NETHER_BRICK_SLAB(6, new String[] { "STEP" }), + NETHER_BRICK_STAIRS, + NETHER_BRICK_WALL, + NETHER_GOLD_ORE(16), + NETHER_PORTAL(new String[] { "PORTAL" }), + NETHER_QUARTZ_ORE(new String[] { "QUARTZ_ORE" }), + NETHER_SPROUTS(16), + NETHER_STAR, + NETHER_WART(new String[] { "NETHER_WARTS", "NETHER_STALK" }), + NETHER_WART_BLOCK, + NOTE_BLOCK, + OAK_BOAT(new String[] { "BOAT" }), + OAK_BUTTON(new String[] { "WOOD_BUTTON" }), + OAK_DOOR(new String[] { "WOODEN_DOOR", "WOOD_DOOR" }), + OAK_FENCE(new String[] { "FENCE" }), + OAK_FENCE_GATE(new String[] { "FENCE_GATE" }), + OAK_LEAVES(new String[] { "LEAVES" }), + OAK_LOG(new String[] { "LOG" }), + OAK_PLANKS(new String[] { "WOOD" }), + OAK_PRESSURE_PLATE(new String[] { "WOOD_PLATE" }), + OAK_SAPLING(new String[] { "SAPLING" }), + OAK_SIGN(new String[] { "SIGN_POST", "SIGN" }), + OAK_SLAB(new String[] { "WOOD_DOUBLE_STEP", "WOOD_STEP", "WOODEN_SLAB" }), + OAK_STAIRS(new String[] { "WOOD_STAIRS" }), + OAK_TRAPDOOR(new String[] { "TRAP_DOOR" }), + OAK_WALL_SIGN(new String[] { "WALL_SIGN" }), + OAK_WOOD(new String[] { "LOG" }), + OBSERVER, + OBSIDIAN, + OCELOT_SPAWN_EGG(98, new String[] { "MONSTER_EGG" }), + ORANGE_BANNER(14, new String[] { "STANDING_BANNER", "BANNER" }), + ORANGE_BED(1, new String[] { "BED_BLOCK", "BED" }), + ORANGE_CARPET(1, new String[] { "CARPET" }), + ORANGE_CONCRETE(1, new String[] { "CONCRETE" }), + ORANGE_CONCRETE_POWDER(1, new String[] { "CONCRETE_POWDER" }), + ORANGE_DYE(14, new String[] { "INK_SACK" }), + ORANGE_GLAZED_TERRACOTTA(1, 12, new String[0]), + ORANGE_SHULKER_BOX, + ORANGE_STAINED_GLASS(1, new String[] { "STAINED_GLASS" }), + ORANGE_STAINED_GLASS_PANE(1, new String[] { "STAINED_GLASS_PANE" }), + ORANGE_TERRACOTTA(1, new String[] { "STAINED_CLAY" }), + ORANGE_TULIP(5, new String[] { "RED_ROSE" }), + ORANGE_WALL_BANNER(14, new String[] { "WALL_BANNER" }), + ORANGE_WOOL(1, new String[] { "WOOL" }), + OXEYE_DAISY(8, new String[] { "RED_ROSE" }), + PACKED_ICE, + PAINTING, + PANDA_SPAWN_EGG(14), + PAPER, + PARROT_SPAWN_EGG(105, new String[] { "MONSTER_EGG" }), + PEONY(5, new String[] { "DOUBLE_PLANT" }), + PETRIFIED_OAK_SLAB(new String[] { "WOOD_STEP" }), + PHANTOM_MEMBRANE(13), + PHANTOM_SPAWN_EGG(0, 13, new String[0]), + PIGLIN_BANNER_PATTERN(16), + PIGLIN_BRUTE_SPAWN_EGG(16), + PIGLIN_SPAWN_EGG(57, new String[] { "MONSTER_EGG" }), + PIG_SPAWN_EGG(90, new String[] { "MONSTER_EGG" }), + PILLAGER_SPAWN_EGG(14), + PINK_BANNER(9, new String[] { "STANDING_BANNER", "BANNER" }), + PINK_BED(6, new String[] { "BED_BLOCK", "BED" }), + PINK_CARPET(6, new String[] { "CARPET" }), + PINK_CONCRETE(6, new String[] { "CONCRETE" }), + PINK_CONCRETE_POWDER(6, new String[] { "CONCRETE_POWDER" }), + PINK_DYE(9, new String[] { "INK_SACK" }), + PINK_GLAZED_TERRACOTTA(6, 12, new String[0]), + PINK_SHULKER_BOX, + PINK_STAINED_GLASS(6, new String[] { "STAINED_GLASS" }), + PINK_STAINED_GLASS_PANE(6, new String[] { "THIN_GLASS", "STAINED_GLASS_PANE" }), + PINK_TERRACOTTA(6, new String[] { "STAINED_CLAY" }), + PINK_TULIP(7, new String[] { "RED_ROSE" }), + PINK_WALL_BANNER(9, new String[] { "WALL_BANNER" }), + PINK_WOOL(6, new String[] { "WOOL" }), + PISTON(new String[] { "PISTON_BASE" }), + PISTON_HEAD(new String[] { "PISTON_EXTENSION" }), + PLAYER_HEAD(3, new String[] { "SKULL", "SKULL_ITEM" }), + PLAYER_WALL_HEAD(3, new String[] { "SKULL", "SKULL_ITEM" }), + PODZOL(2, new String[] { "DIRT" }), + POISONOUS_POTATO, + POLAR_BEAR_SPAWN_EGG(102, new String[] { "MONSTER_EGG" }), + POLISHED_ANDESITE(6, new String[] { "STONE" }), + POLISHED_ANDESITE_SLAB, + POLISHED_ANDESITE_STAIRS, + POLISHED_BASALT(16), + POLISHED_BLACKSTONE(16), + POLISHED_BLACKSTONE_BRICKS(16), + POLISHED_BLACKSTONE_BRICK_SLAB(16), + POLISHED_BLACKSTONE_BRICK_STAIRS(16), + POLISHED_BLACKSTONE_BRICK_WALL(16), + POLISHED_BLACKSTONE_BUTTON(16), + POLISHED_BLACKSTONE_PRESSURE_PLATE(16), + POLISHED_BLACKSTONE_SLAB(16), + POLISHED_BLACKSTONE_STAIRS(16), + POLISHED_BLACKSTONE_WALL(16), + POLISHED_DIORITE(4, new String[] { "STONE" }), + POLISHED_DIORITE_SLAB, + POLISHED_DIORITE_STAIRS, + POLISHED_GRANITE(2, new String[] { "STONE" }), + POLISHED_GRANITE_SLAB, + POLISHED_GRANITE_STAIRS, + POPPED_CHORUS_FRUIT(new String[] { "CHORUS_FRUIT_POPPED" }), + POPPY(new String[] { "RED_ROSE" }), + PORKCHOP(new String[] { "PORK" }), + POTATO(new String[] { "POTATO_ITEM" }), + POTATOES(new String[] { "POTATO" }), + POTION, + POTTED_ACACIA_SAPLING(4, new String[] { "SAPLING", "FLOWER_POT" }), + POTTED_ALLIUM(2, new String[] { "RED_ROSE", "FLOWER_POT" }), + POTTED_AZURE_BLUET(3, new String[] { "RED_ROSE", "FLOWER_POT" }), + POTTED_BAMBOO, + POTTED_BIRCH_SAPLING(2, new String[] { "SAPLING", "FLOWER_POT" }), + POTTED_BLUE_ORCHID(1, new String[] { "RED_ROSE", "FLOWER_POT" }), + POTTED_BROWN_MUSHROOM(new String[] { "FLOWER_POT" }), + POTTED_CACTUS(new String[] { "FLOWER_POT" }), + POTTED_CORNFLOWER, + POTTED_CRIMSON_FUNGUS(16), + POTTED_CRIMSON_ROOTS(16), + POTTED_DANDELION(new String[] { "YELLOW_FLOWER", "FLOWER_POT" }), + POTTED_DARK_OAK_SAPLING(5, new String[] { "SAPLING", "FLOWER_POT" }), + POTTED_DEAD_BUSH(new String[] { "FLOWER_POT" }), + POTTED_FERN(2, new String[] { "LONG_GRASS", "FLOWER_POT" }), + POTTED_JUNGLE_SAPLING(3, new String[] { "SAPLING", "FLOWER_POT" }), + POTTED_LILY_OF_THE_VALLEY, + POTTED_OAK_SAPLING(new String[] { "SAPLING", "FLOWER_POT" }), + POTTED_ORANGE_TULIP(5, new String[] { "RED_ROSE", "FLOWER_POT" }), + POTTED_OXEYE_DAISY(8, new String[] { "RED_ROSE", "FLOWER_POT" }), + POTTED_PINK_TULIP(7, new String[] { "RED_ROSE", "FLOWER_POT" }), + POTTED_POPPY(new String[] { "RED_ROSE", "FLOWER_POT" }), + POTTED_RED_MUSHROOM(new String[] { "FLOWER_POT" }), + POTTED_RED_TULIP(4, new String[] { "RED_ROSE", "FLOWER_POT" }), + POTTED_SPRUCE_SAPLING(1, new String[] { "SAPLING", "FLOWER_POT" }), + POTTED_WARPED_FUNGUS(16), + POTTED_WARPED_ROOTS(16), + POTTED_WHITE_TULIP(6, new String[] { "RED_ROSE", "FLOWER_POT" }), + POTTED_WITHER_ROSE, + POWERED_RAIL, + PRISMARINE, + PRISMARINE_BRICKS(2, new String[] { "PRISMARINE" }), + PRISMARINE_BRICK_SLAB(4, new String[] { "STEP" }), + PRISMARINE_BRICK_STAIRS(13), + PRISMARINE_CRYSTALS, + PRISMARINE_SHARD, + PRISMARINE_SLAB(13), + PRISMARINE_STAIRS(13), + PRISMARINE_WALL, + PUFFERFISH(3, new String[] { "RAW_FISH" }), + PUFFERFISH_BUCKET(0, 13, new String[0]), + PUFFERFISH_SPAWN_EGG(0, 13, new String[0]), + PUMPKIN, + PUMPKIN_PIE, + PUMPKIN_SEEDS, + PUMPKIN_STEM, + PURPLE_BANNER(5, new String[] { "STANDING_BANNER", "BANNER" }), + PURPLE_BED(10, new String[] { "BED_BLOCK", "BED" }), + PURPLE_CARPET(10, new String[] { "CARPET" }), + PURPLE_CONCRETE(10, new String[] { "CONCRETE" }), + PURPLE_CONCRETE_POWDER(10, new String[] { "CONCRETE_POWDER" }), + PURPLE_DYE(5, new String[] { "INK_SACK" }), + PURPLE_GLAZED_TERRACOTTA(10, 12, new String[0]), + PURPLE_SHULKER_BOX, + PURPLE_STAINED_GLASS(10, new String[] { "STAINED_GLASS" }), + PURPLE_STAINED_GLASS_PANE(10, new String[] { "THIN_GLASS", "STAINED_GLASS_PANE" }), + PURPLE_TERRACOTTA(10, new String[] { "STAINED_CLAY" }), + PURPLE_WALL_BANNER(5, new String[] { "WALL_BANNER" }), + PURPLE_WOOL(10, new String[] { "WOOL" }), + PURPUR_BLOCK, + PURPUR_PILLAR, + PURPUR_SLAB(new String[] { "PURPUR_DOUBLE_SLAB" }), + PURPUR_STAIRS, + QUARTZ, + QUARTZ_BLOCK, + QUARTZ_BRICKS(16), + QUARTZ_PILLAR(2, new String[] { "QUARTZ_BLOCK" }), + QUARTZ_SLAB(7, new String[] { "STEP" }), + QUARTZ_STAIRS, + RABBIT, + RABBIT_FOOT, + RABBIT_HIDE, + RABBIT_SPAWN_EGG(101, new String[] { "MONSTER_EGG" }), + RABBIT_STEW, + RAIL(new String[] { "RAILS" }), + RAVAGER_SPAWN_EGG(14), + REDSTONE, + REDSTONE_BLOCK, + REDSTONE_LAMP(new String[] { "REDSTONE_LAMP_ON", "REDSTONE_LAMP_OFF" }), + REDSTONE_ORE(new String[] { "GLOWING_REDSTONE_ORE" }), + REDSTONE_TORCH(new String[] { "REDSTONE_TORCH_OFF", "REDSTONE_TORCH_ON" }), + REDSTONE_WALL_TORCH, + REDSTONE_WIRE, + RED_BANNER(1, new String[] { "STANDING_BANNER", "BANNER" }), + RED_BED(0, new String[] { "BED_BLOCK", "BED" }), + RED_CARPET(14, new String[] { "CARPET" }), + RED_CONCRETE(14, new String[] { "CONCRETE" }), + RED_CONCRETE_POWDER(14, new String[] { "CONCRETE_POWDER" }), + RED_DYE(1, new String[] { "INK_SACK", "ROSE_RED" }), + RED_GLAZED_TERRACOTTA(14, 12, new String[0]), + RED_MUSHROOM, + RED_MUSHROOM_BLOCK(new String[] { "RED_MUSHROOM", "HUGE_MUSHROOM_2" }), + RED_NETHER_BRICKS(new String[] { "RED_NETHER_BRICK" }), + RED_NETHER_BRICK_SLAB(4, new String[] { "STEP" }), + RED_NETHER_BRICK_STAIRS, + RED_NETHER_BRICK_WALL, + RED_SAND(1, new String[] { "SAND" }), + RED_SANDSTONE, + RED_SANDSTONE_SLAB(new String[] { "DOUBLE_STONE_SLAB2", "STONE_SLAB2" }), + RED_SANDSTONE_STAIRS, + RED_SANDSTONE_WALL, + RED_SHULKER_BOX, + RED_STAINED_GLASS(14, new String[] { "STAINED_GLASS" }), + RED_STAINED_GLASS_PANE(14, new String[] { "THIN_GLASS", "STAINED_GLASS_PANE" }), + RED_TERRACOTTA(14, new String[] { "STAINED_CLAY" }), + RED_TULIP(4, new String[] { "RED_ROSE" }), + RED_WALL_BANNER(1, new String[] { "WALL_BANNER" }), + RED_WOOL(14, new String[] { "WOOL" }), + REPEATER(new String[] { "DIODE_BLOCK_ON", "DIODE_BLOCK_OFF", "DIODE" }), + REPEATING_COMMAND_BLOCK(new String[] { "COMMAND", "COMMAND_REPEATING" }), + RESPAWN_ANCHOR(16), + ROSE_BUSH(4, new String[] { "DOUBLE_PLANT" }), + ROTTEN_FLESH, + SADDLE, + SALMON(1, new String[] { "RAW_FISH" }), + SALMON_BUCKET(0, 13, new String[0]), + SALMON_SPAWN_EGG(0, 13, new String[0]), + SAND, + SANDSTONE, + SANDSTONE_SLAB(1, new String[] { "DOUBLE_STEP", "STEP", "STONE_SLAB" }), + SANDSTONE_STAIRS, + SANDSTONE_WALL, + SCAFFOLDING(0, 14, new String[0]), + SCUTE(13), + SEAGRASS(0, 13, new String[0]), + SEA_LANTERN, + SEA_PICKLE(13), + SHEARS, + SHEEP_SPAWN_EGG(91, new String[] { "MONSTER_EGG" }), + SHIELD, + SHROOMLIGHT(16), + SHULKER_BOX(new String[] { "PURPLE_SHULKER_BOX" }), + SHULKER_SHELL, + SHULKER_SPAWN_EGG(69, new String[] { "MONSTER_EGG" }), + SILVERFISH_SPAWN_EGG(60, new String[] { "MONSTER_EGG" }), + SKELETON_HORSE_SPAWN_EGG(28, new String[] { "MONSTER_EGG" }), + SKELETON_SKULL(new String[] { "SKULL", "SKULL_ITEM" }), + SKELETON_SPAWN_EGG(51, new String[] { "MONSTER_EGG" }), + SKELETON_WALL_SKULL(new String[] { "SKULL", "SKULL_ITEM" }), + SKULL_BANNER_PATTERN, + SLIME_BALL, + SLIME_BLOCK, + SLIME_SPAWN_EGG(55, new String[] { "MONSTER_EGG" }), + SMITHING_TABLE, + SMOKER(0, 14, new String[0]), + SMOOTH_QUARTZ(0, 13, new String[0]), + SMOOTH_QUARTZ_SLAB(7, new String[] { "STEP" }), + SMOOTH_QUARTZ_STAIRS, + SMOOTH_RED_SANDSTONE(2, new String[] { "RED_SANDSTONE" }), + SMOOTH_RED_SANDSTONE_SLAB(new String[] { "STONE_SLAB2" }), + SMOOTH_RED_SANDSTONE_STAIRS, + SMOOTH_SANDSTONE(2, new String[] { "SANDSTONE" }), + SMOOTH_SANDSTONE_SLAB(new String[] { "STEP" }), + SMOOTH_SANDSTONE_STAIRS, + SMOOTH_STONE(new String[] { "STEP" }), + SMOOTH_STONE_SLAB(new String[] { "STEP" }), + SNOW, + SNOWBALL(new String[] { "SNOW_BALL" }), + SNOW_BLOCK, + SOUL_CAMPFIRE(16), + SOUL_FIRE(16), + SOUL_LANTERN(16), + SOUL_SAND, + SOUL_SOIL(16), + SOUL_TORCH(16), + SOUL_WALL_TORCH(16), + SPAWNER(new String[] { "MOB_SPAWNER" }), + SPECTRAL_ARROW(0, 9, new String[0]), + SPIDER_EYE, + SPIDER_SPAWN_EGG(52, new String[] { "MONSTER_EGG" }), + SPLASH_POTION, + SPONGE, + SPRUCE_BOAT(new String[] { "BOAT_SPRUCE" }), + SPRUCE_BUTTON(new String[] { "WOOD_BUTTON" }), + SPRUCE_DOOR(new String[] { "SPRUCE_DOOR", "SPRUCE_DOOR_ITEM" }), + SPRUCE_FENCE, + SPRUCE_FENCE_GATE, + SPRUCE_LEAVES(1, new String[] { "LEAVES", "LEAVES_2" }), + SPRUCE_LOG(1, new String[] { "LOG" }), + SPRUCE_PLANKS(1, new String[] { "WOOD" }), + SPRUCE_PRESSURE_PLATE(new String[] { "WOOD_PLATE" }), + SPRUCE_SAPLING(1, new String[] { "SAPLING" }), + SPRUCE_SIGN(new String[] { "SIGN_POST", "SIGN" }), + SPRUCE_SLAB(1, new String[] { "WOOD_DOUBLE_STEP", "WOOD_STEP", "WOODEN_SLAB" }), + SPRUCE_STAIRS(new String[] { "SPRUCE_WOOD_STAIRS" }), + SPRUCE_TRAPDOOR(new String[] { "TRAP_DOOR" }), + SPRUCE_WALL_SIGN(new String[] { "WALL_SIGN" }), + SPRUCE_WOOD(1, new String[] { "LOG" }), + SQUID_SPAWN_EGG(94, new String[] { "MONSTER_EGG" }), + STICK, + STICKY_PISTON(new String[] { "PISTON_BASE", "PISTON_STICKY_BASE" }), + STONE, + STONECUTTER(14), + STONE_AXE, + STONE_BRICKS(new String[] { "SMOOTH_BRICK" }), + STONE_BRICK_SLAB(4, new String[] { "DOUBLE_STEP", "STEP", "STONE_SLAB" }), + STONE_BRICK_STAIRS(new String[] { "SMOOTH_STAIRS" }), + STONE_BRICK_WALL, + STONE_BUTTON, + STONE_HOE, + STONE_PICKAXE, + STONE_PRESSURE_PLATE(new String[] { "STONE_PLATE" }), + STONE_SHOVEL(new String[] { "STONE_SPADE" }), + STONE_SLAB(new String[] { "DOUBLE_STEP", "STEP" }), + STONE_STAIRS, + STONE_SWORD, + STRAY_SPAWN_EGG(6, new String[] { "MONSTER_EGG" }), + STRIDER_SPAWN_EGG(16), + STRING, + STRIPPED_ACACIA_LOG(new String[] { "LOG_2" }), + STRIPPED_ACACIA_WOOD(new String[] { "LOG_2" }), + STRIPPED_BIRCH_LOG(2, new String[] { "LOG" }), + STRIPPED_BIRCH_WOOD(2, new String[] { "LOG" }), + STRIPPED_CRIMSON_HYPHAE(16), + STRIPPED_CRIMSON_STEM(16), + STRIPPED_DARK_OAK_LOG(new String[] { "LOG" }), + STRIPPED_DARK_OAK_WOOD(new String[] { "LOG" }), + STRIPPED_JUNGLE_LOG(3, new String[] { "LOG" }), + STRIPPED_JUNGLE_WOOD(3, new String[] { "LOG" }), + STRIPPED_OAK_LOG(new String[] { "LOG" }), + STRIPPED_OAK_WOOD(new String[] { "LOG" }), + STRIPPED_SPRUCE_LOG(1, new String[] { "LOG" }), + STRIPPED_SPRUCE_WOOD(1, new String[] { "LOG" }), + STRIPPED_WARPED_HYPHAE(16), + STRIPPED_WARPED_STEM(16), + STRUCTURE_BLOCK, + STRUCTURE_VOID(10, new String[] { "BARRIER" }), + SUGAR, + SUGAR_CANE(new String[] { "SUGAR_CANE_BLOCK" }), + SUNFLOWER(new String[] { "DOUBLE_PLANT" }), + SUSPICIOUS_STEW(0, 14, new String[0]), + SWEET_BERRIES(14), + SWEET_BERRY_BUSH(0, 14, new String[0]), + TALL_GRASS(2, new String[] { "DOUBLE_PLANT" }), + TALL_SEAGRASS(2, 13, new String[0]), + TARGET(16), + TERRACOTTA(new String[] { "STAINED_CLAY" }), + TIPPED_ARROW(0, 9, new String[0]), + TNT, + TNT_MINECART(new String[] { "EXPLOSIVE_MINECART" }), + TORCH, + TOTEM_OF_UNDYING(new String[] { "TOTEM" }), + TRADER_LLAMA_SPAWN_EGG(103, 14, new String[0]), + TRAPPED_CHEST, + TRIDENT(13), + TRIPWIRE, + TRIPWIRE_HOOK, + TROPICAL_FISH(2, new String[] { "RAW_FISH" }), + TROPICAL_FISH_BUCKET(0, 13, new String[] { "BUCKET", "WATER_BUCKET" }), + TROPICAL_FISH_SPAWN_EGG(0, 13, new String[] { "MONSTER_EGG" }), + TUBE_CORAL(13), + TUBE_CORAL_BLOCK(13), + TUBE_CORAL_FAN(13), + TUBE_CORAL_WALL_FAN, + TURTLE_EGG(0, 13, new String[0]), + TURTLE_HELMET(0, 13, new String[0]), + TURTLE_SPAWN_EGG(0, 13, new String[0]), + TWISTING_VINES(16), + TWISTING_VINES_PLANT(16), + VEX_SPAWN_EGG(35, new String[] { "MONSTER_EGG" }), + VILLAGER_SPAWN_EGG(120, new String[] { "MONSTER_EGG" }), + VINDICATOR_SPAWN_EGG(36, new String[] { "MONSTER_EGG" }), + VINE, + VOID_AIR(new String[] { "AIR" }), + WALL_TORCH(new String[] { "TORCH" }), + WANDERING_TRADER_SPAWN_EGG(0, 14, new String[0]), + WARPED_BUTTON(16), + WARPED_DOOR(16), + WARPED_FENCE(16), + WARPED_FENCE_GATE(16), + WARPED_FUNGUS(16), + WARPED_FUNGUS_ON_A_STICK(16), + WARPED_HYPHAE(16), + WARPED_NYLIUM(16), + WARPED_PLANKS(16), + WARPED_PRESSURE_PLATE(16), + WARPED_ROOTS(16), + WARPED_SIGN(0, 16, new String[] { "SIGN_POST" }), + WARPED_SLAB(16), + WARPED_STAIRS(16), + WARPED_STEM(16), + WARPED_TRAPDOOR(16), + WARPED_WALL_SIGN(0, 16, new String[] { "WALL_SIGN" }), + WARPED_WART_BLOCK(16), + WATER(new String[] { "STATIONARY_WATER" }), + WATER_BUCKET, + WEEPING_VINES(16), + WEEPING_VINES_PLANT(16), + WET_SPONGE(1, new String[] { "SPONGE" }), + WHEAT(new String[] { "CROPS" }), + WHEAT_SEEDS(new String[] { "SEEDS" }), + WHITE_BANNER(15, new String[] { "STANDING_BANNER", "BANNER" }), + WHITE_BED(new String[] { "BED_BLOCK", "BED" }), + WHITE_CARPET(new String[] { "CARPET" }), + WHITE_CONCRETE(new String[] { "CONCRETE" }), + WHITE_CONCRETE_POWDER(new String[] { "CONCRETE_POWDER" }), + WHITE_DYE(15, 14, new String[] { "INK_SACK", "BONE_MEAL" }), + WHITE_GLAZED_TERRACOTTA(0, 12, new String[] { "STAINED_CLAY" }), + WHITE_SHULKER_BOX, + WHITE_STAINED_GLASS(new String[] { "STAINED_GLASS" }), + WHITE_STAINED_GLASS_PANE(new String[] { "THIN_GLASS", "STAINED_GLASS_PANE" }), + WHITE_TERRACOTTA(new String[] { "STAINED_CLAY", "TERRACOTTA" }), + WHITE_TULIP(6, new String[] { "RED_ROSE" }), + WHITE_WALL_BANNER(15, new String[] { "WALL_BANNER" }), + WHITE_WOOL(new String[] { "WOOL" }), + WITCH_SPAWN_EGG(66, new String[] { "MONSTER_EGG" }), + WITHER_ROSE(0, 14, new String[0]), + WITHER_SKELETON_SKULL(1, new String[] { "SKULL", "SKULL_ITEM" }), + WITHER_SKELETON_SPAWN_EGG(5, new String[] { "MONSTER_EGG" }), + WITHER_SKELETON_WALL_SKULL(1, new String[] { "SKULL", "SKULL_ITEM" }), + WOLF_SPAWN_EGG(95, new String[] { "MONSTER_EGG" }), + WOODEN_AXE(new String[] { "WOOD_AXE" }), + WOODEN_HOE(new String[] { "WOOD_HOE" }), + WOODEN_PICKAXE(new String[] { "WOOD_PICKAXE" }), + WOODEN_SHOVEL(new String[] { "WOOD_SPADE" }), + WOODEN_SWORD(new String[] { "WOOD_SWORD" }), + WRITABLE_BOOK(new String[] { "BOOK_AND_QUILL" }), + WRITTEN_BOOK, + YELLOW_BANNER(11, new String[] { "STANDING_BANNER", "BANNER" }), + YELLOW_BED(4, new String[] { "BED_BLOCK", "BED" }), + YELLOW_CARPET(4, new String[] { "CARPET" }), + YELLOW_CONCRETE(4, new String[] { "CONCRETE" }), + YELLOW_CONCRETE_POWDER(4, new String[] { "CONCRETE_POWDER" }), + YELLOW_DYE(11, new String[] { "INK_SACK", "DANDELION_YELLOW" }), + YELLOW_GLAZED_TERRACOTTA(4, 12, new String[] { "STAINED_CLAY", "YELLOW_TERRACOTTA" }), + YELLOW_SHULKER_BOX, + YELLOW_STAINED_GLASS(4, new String[] { "STAINED_GLASS" }), + YELLOW_STAINED_GLASS_PANE(4, new String[] { "THIN_GLASS", "STAINED_GLASS_PANE" }), + YELLOW_TERRACOTTA(4, new String[] { "STAINED_CLAY" }), + YELLOW_WALL_BANNER(11, new String[] { "WALL_BANNER" }), + YELLOW_WOOL(4, new String[] { "WOOL" }), + ZOGLIN_SPAWN_EGG(16), + ZOMBIE_HEAD(2, new String[] { "SKULL", "SKULL_ITEM" }), + ZOMBIE_HORSE_SPAWN_EGG(29, new String[] { "MONSTER_EGG" }), + ZOMBIE_SPAWN_EGG(54, new String[] { "MONSTER_EGG" }), + ZOMBIE_VILLAGER_SPAWN_EGG(27, new String[] { "MONSTER_EGG" }), + ZOMBIE_WALL_HEAD(2, new String[] { "SKULL", "SKULL_ITEM" }), + ZOMBIFIED_PIGLIN_SPAWN_EGG(57, new String[] { "MONSTER_EGG", "ZOMBIE_PIGMAN_SPAWN_EGG" }); + + public static final XMaterial[] VALUES; + private static final Map NAMES; + private static final Cache NAME_CACHE; + private static final LoadingCache CACHED_REGEX; + private static final byte MAX_DATA_VALUE = 120; + private static final byte UNKNOWN_DATA_VALUE = -1; + private static final short MAX_ID = 2267; + private static final Set DUPLICATED; + private final byte data; + private final byte version; + @Nonnull + private final String[] legacy; + @Nullable + private final Material material; + + private XMaterial(@Nonnull final int data, final int version, final String[] legacy) { + this.data = (byte)data; + this.version = (byte)version; + this.legacy = legacy; + Material mat = null; + if ((!Data.ISFLAT && this.isDuplicated()) || (mat = Material.getMaterial(this.name())) == null) { + for (int i = legacy.length - 1; i >= 0; --i) { + mat = Material.getMaterial(legacy[i]); + if (mat != null) { + break; + } + } + } + this.material = mat; + } + + private XMaterial(final int data, final String[] legacy) { + this(data, 0, legacy); + } + + private XMaterial(final int version) { + this(0, version, new String[0]); + } + + private XMaterial() { + this(0, 0, new String[0]); + } + + private XMaterial(final String[] legacy) { + this(0, 0, legacy); + } + + public static boolean isNewVersion() { + return Data.ISFLAT; + } + + public static boolean isOneEight() { + return !supports(9); + } + + @Nonnull + private static Optional getIfPresent(@Nonnull final String name) { + return Optional.ofNullable(XMaterial.NAMES.get(name)); + } + + public static int getVersion() { + return Data.VERSION; + } + + @Nullable + private static XMaterial requestOldXMaterial(@Nonnull final String name, final byte data) { + final String holder = name + data; + final XMaterial cache = XMaterial.NAME_CACHE.getIfPresent(holder); + if (cache != null) { + return cache; + } + for (final XMaterial material : XMaterial.VALUES) { + if ((data == -1 || data == material.data) && material.anyMatchLegacy(name)) { + XMaterial.NAME_CACHE.put(holder, material); + return material; + } + } + return null; + } + + @Nonnull + public static Optional matchXMaterial(@Nonnull final String name) { + Validate.notEmpty(name, "Cannot match a material with null or empty material name"); + final Optional oldMatch = matchXMaterialWithData(name); + return oldMatch.isPresent() ? oldMatch : matchDefinedXMaterial(format(name), (byte)(-1)); + } + + @Nonnull + private static Optional matchXMaterialWithData(@Nonnull final String name) { + final int index = name.indexOf(58); + if (index != -1) { + final String mat = format(name.substring(0, index)); + try { + final byte data = (byte)Integer.parseInt(StringUtils.deleteWhitespace(name.substring(index + 1))); + return (data >= 0 && data < 120) ? matchDefinedXMaterial(mat, data) : matchDefinedXMaterial(mat, (byte)(-1)); + } + catch (final NumberFormatException ignored) { + return matchDefinedXMaterial(mat, (byte)(-1)); + } + } + return Optional.empty(); + } + + @Nonnull + public static XMaterial matchXMaterial(@Nonnull final Material material) { + Objects.requireNonNull(material, "Cannot match null material"); + return matchDefinedXMaterial(material.name(), (byte)(-1)).get(); + } + + @Nonnull + public static XMaterial matchXMaterial(@Nonnull final ItemStack item) { + Objects.requireNonNull(item, "Cannot match null ItemStack"); + final String material = item.getType().name(); + final byte data = (byte)((Data.ISFLAT || item.getType().getMaxDurability() > 0) ? 0 : item.getDurability()); + return matchDefinedXMaterial(material, data).get(); + } + + @Nonnull + private static Optional matchDefinedXMaterial(@Nonnull final String name, final byte data) { + Boolean duplicated = null; + if (data <= 0 && (Data.ISFLAT || !(duplicated = isDuplicated(name)))) { + final Optional xMaterial = getIfPresent(name); + if (xMaterial.isPresent()) { + return xMaterial; + } + } + final XMaterial oldXMaterial = requestOldXMaterial(name, data); + if (oldXMaterial == null) { + return (data > 0 && name.endsWith("MAP")) ? Optional.of(XMaterial.FILLED_MAP) : Optional.empty(); + } + if (!Data.ISFLAT && oldXMaterial.isPlural()) { + if (duplicated == null) { + if (!isDuplicated(name)) { + return Optional.of(oldXMaterial); + } + } + else if (!duplicated) { + return Optional.of(oldXMaterial); + } + return getIfPresent(name); + } + return Optional.of(oldXMaterial); + } + + private static boolean isDuplicated(@Nonnull final String name) { + return XMaterial.DUPLICATED.contains(name); + } + + @Nonnull + @Deprecated + public static Optional matchXMaterial(final int id, final byte data) { + if (id < 0 || id > 2267 || data < 0) { + return Optional.empty(); + } + for (final XMaterial materials : XMaterial.VALUES) { + if (materials.data == data && materials.getId() == id) { + return Optional.of(materials); + } + } + return Optional.empty(); + } + + @Nonnull + protected static String format(@Nonnull final String name) { + final int len = name.length(); + final char[] chs = new char[len]; + int count = 0; + boolean appendUnderline = false; + for (int i = 0; i < len; ++i) { + final char ch = name.charAt(i); + if (!appendUnderline && count != 0 && (ch == '-' || ch == ' ' || ch == '_') && chs[count] != '_') { + appendUnderline = true; + } + else { + boolean number = false; + if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (number = (ch >= '0' && ch <= '9'))) { + if (appendUnderline) { + chs[count++] = '_'; + appendUnderline = false; + } + if (number) { + chs[count++] = ch; + } + else { + chs[count++] = (char)(ch & '_'); + } + } + } + } + return new String(chs, 0, count); + } + + public static boolean supports(final int version) { + return Data.VERSION >= version; + } + + @Nonnull + public static String getMajorVersion(@Nonnull String version) { + Validate.notEmpty(version, "Cannot get major Minecraft version from null or empty string"); + int index = version.lastIndexOf("MC:"); + if (index != -1) { + version = version.substring(index + 4, version.length() - 1); + } + else if (version.endsWith("SNAPSHOT")) { + index = version.indexOf(45); + version = version.substring(0, index); + } + final int lastDot = version.lastIndexOf(46); + if (version.indexOf(46) != lastDot) { + version = version.substring(0, lastDot); + } + return version; + } + + public String[] getLegacy() { + return this.legacy; + } + + private boolean isPlural() { + return this.name().charAt(this.name().length() - 1) == 'S'; + } + + public boolean isOneOf(@Nullable final Collection materials) { + if (materials == null || materials.isEmpty()) { + return false; + } + final String name = this.name(); + for (String comp : materials) { + final String checker = comp.toUpperCase(Locale.ENGLISH); + if (checker.startsWith("CONTAINS:")) { + comp = format(checker.substring(9)); + if (name.contains(comp)) { + return true; + } + continue; + } + else if (checker.startsWith("REGEX:")) { + comp = comp.substring(6); + final Pattern pattern = XMaterial.CACHED_REGEX.getUnchecked(comp); + if (pattern != null && pattern.matcher(name).matches()) { + return true; + } + continue; + } + else { + final Optional xMat = matchXMaterial(comp); + if (xMat.isPresent() && xMat.get() == this) { + return true; + } + continue; + } + } + return false; + } + + @Nonnull + public ItemStack setType(@Nonnull final ItemStack item) { + Objects.requireNonNull(item, "Cannot set material for null ItemStack"); + final Material material = this.parseMaterial(); + Objects.requireNonNull(material, () -> "Unsupported material: " + this.name()); + item.setType(material); + if (!Data.ISFLAT && material.getMaxDurability() <= 0) { + item.setDurability(this.data); + } + return item; + } + + private boolean anyMatchLegacy(@Nonnull final String name) { + for (int i = this.legacy.length - 1; i >= 0; --i) { + final String legacy = this.legacy[i]; + if (name.equals(legacy)) { + return true; + } + } + return false; + } + + @Nonnull + @Override + public String toString() { + return WordUtils.capitalize(this.name().replace('_', ' ').toLowerCase(Locale.ENGLISH)); + } + + public int getId() { + if (this.data != 0 || this.version >= 13) { + return -1; + } + final Material material = this.parseMaterial(); + if (material == null) { + return -1; + } + if (Data.ISFLAT && !material.isLegacy()) { + return -1; + } + return material.getId(); + } + + public byte getData() { + return this.data; + } + + @NotNull + public ItemStack parseItem() { + final Material material = this.parseMaterial(); + if (material == null) { + return null; + } + return Data.ISFLAT ? new ItemStack(material) : new ItemStack(material, 1, this.data); + } + + public Material parseMaterial() { + return this.material; + } + + public boolean isSimilar(@Nonnull final ItemStack item) { + Objects.requireNonNull(item, "Cannot compare with null ItemStack"); + return item.getType() == this.parseMaterial() && (Data.ISFLAT || item.getDurability() == this.data || item.getType().getMaxDurability() <= 0); + } + + public boolean isSupported() { + return this.material != null; + } + + public byte getMaterialVersion() { + return this.version; + } + + private boolean isDuplicated() { + final String name = this.name(); + return name.equals("MELON") || name.equals("CARROT") || name.equals("POTATO") || name.equals("BEETROOT") || name.equals("GRASS") || name.equals("BROWN_MUSHROOM") || name.equals("BRICK") || name.equals("NETHER_BRICK") || name.equals("DARK_OAK_DOOR") || name.equals("ACACIA_DOOR") || name.equals("BIRCH_DOOR") || name.equals("JUNGLE_DOOR") || name.equals("SPRUCE_DOOR") || name.equals("CAULDRON") || name.equals("BREWING_STAND") || name.equals("FLOWER_POT"); + } + + static { + VALUES = values(); + NAMES = new HashMap(); + NAME_CACHE = CacheBuilder.newBuilder().expireAfterAccess(1L, TimeUnit.HOURS).build(); + CACHED_REGEX = CacheBuilder.newBuilder().expireAfterAccess(3L, TimeUnit.HOURS).build((CacheLoader)new CacheLoader() { + @Override + public Pattern load(@Nonnull final String str) { + try { + return Pattern.compile(str); + } + catch (final PatternSyntaxException ex) { + ex.printStackTrace(); + return null; + } + } + }); + for (final XMaterial material : XMaterial.VALUES) { + XMaterial.NAMES.put(material.name(), material); + } + if (Data.ISFLAT) { + DUPLICATED = null; + } + else { + final List duplications = Arrays.asList(XMaterial.MELON, XMaterial.CARROT, XMaterial.POTATO, XMaterial.BEETROOT, XMaterial.GRASS, XMaterial.BROWN_MUSHROOM, XMaterial.BRICK, XMaterial.NETHER_BRICK, XMaterial.DARK_OAK_DOOR, XMaterial.ACACIA_DOOR, XMaterial.BIRCH_DOOR, XMaterial.JUNGLE_DOOR, XMaterial.SPRUCE_DOOR, XMaterial.CAULDRON, XMaterial.BREWING_STAND, XMaterial.FLOWER_POT); + final Set duplicatedNames = new HashSet(50); + for (final XMaterial dupe : duplications) { + duplicatedNames.add(dupe.name()); + duplicatedNames.addAll(Arrays.asList(dupe.legacy)); + } + DUPLICATED = duplicatedNames; + } + } + + private static final class Data + { + private static final int VERSION; + private static final boolean ISFLAT; + + static { + VERSION = Integer.parseInt(XMaterial.getMajorVersion(Bukkit.getVersion()).substring(2)); + ISFLAT = XMaterial.supports(13); + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/nms/AxisAlignedBB.java b/src/main/java/me/frep/vulcan/spigot/util/nms/AxisAlignedBB.java new file mode 100644 index 0000000..ead4c03 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/nms/AxisAlignedBB.java @@ -0,0 +1,275 @@ +package me.frep.vulcan.spigot.util.nms; + +public class AxisAlignedBB +{ + public final double minX; + public final double minY; + public final double minZ; + public final double maxX; + public final double maxY; + public final double maxZ; + + public AxisAlignedBB(final double x1, final double y1, final double z1, final double x2, final double y2, final double z2) { + this.minX = Math.min(x1, x2); + this.minY = Math.min(y1, y2); + this.minZ = Math.min(z1, z2); + this.maxX = Math.max(x1, x2); + this.maxY = Math.max(y1, y2); + this.maxZ = Math.max(z1, z2); + } + + public AxisAlignedBB(final BlockPos pos1, final BlockPos pos2) { + this.minX = pos1.getX(); + this.minY = pos1.getY(); + this.minZ = pos1.getZ(); + this.maxX = pos2.getX(); + this.maxY = pos2.getY(); + this.maxZ = pos2.getZ(); + } + + public AxisAlignedBB addCoord(final double x, final double y, final double z) { + double d0 = this.minX; + double d2 = this.minY; + double d3 = this.minZ; + double d4 = this.maxX; + double d5 = this.maxY; + double d6 = this.maxZ; + if (x < 0.0) { + d0 += x; + } + else if (x > 0.0) { + d4 += x; + } + if (y < 0.0) { + d2 += y; + } + else if (y > 0.0) { + d5 += y; + } + if (z < 0.0) { + d3 += z; + } + else if (z > 0.0) { + d6 += z; + } + return new AxisAlignedBB(d0, d2, d3, d4, d5, d6); + } + + public AxisAlignedBB expand(final double x, final double y, final double z) { + final double d0 = this.minX - x; + final double d2 = this.minY - y; + final double d3 = this.minZ - z; + final double d4 = this.maxX + x; + final double d5 = this.maxY + y; + final double d6 = this.maxZ + z; + return new AxisAlignedBB(d0, d2, d3, d4, d5, d6); + } + + public static String spigot() { + return "%%__USER__%%"; + } + + public static String nonce() { + return "%%__NONCE__%%"; + } + + public static String resource() { + return "%%__RESOURCE__%%"; + } + + public AxisAlignedBB union(final AxisAlignedBB other) { + final double d0 = Math.min(this.minX, other.minX); + final double d2 = Math.min(this.minY, other.minY); + final double d3 = Math.min(this.minZ, other.minZ); + final double d4 = Math.max(this.maxX, other.maxX); + final double d5 = Math.max(this.maxY, other.maxY); + final double d6 = Math.max(this.maxZ, other.maxZ); + return new AxisAlignedBB(d0, d2, d3, d4, d5, d6); + } + + public static AxisAlignedBB fromBounds(final double x1, final double y1, final double z1, final double x2, final double y2, final double z2) { + final double d0 = Math.min(x1, x2); + final double d2 = Math.min(y1, y2); + final double d3 = Math.min(z1, z2); + final double d4 = Math.max(x1, x2); + final double d5 = Math.max(y1, y2); + final double d6 = Math.max(z1, z2); + return new AxisAlignedBB(d0, d2, d3, d4, d5, d6); + } + + public AxisAlignedBB offset(final double x, final double y, final double z) { + return new AxisAlignedBB(this.minX + x, this.minY + y, this.minZ + z, this.maxX + x, this.maxY + y, this.maxZ + z); + } + + public double calculateXOffset(final AxisAlignedBB other, double offsetX) { + if (other.maxY > this.minY && other.minY < this.maxY && other.maxZ > this.minZ && other.minZ < this.maxZ) { + if (offsetX > 0.0 && other.maxX <= this.minX) { + final double d1 = this.minX - other.maxX; + if (d1 < offsetX) { + offsetX = d1; + } + } + else if (offsetX < 0.0 && other.minX >= this.maxX) { + final double d2 = this.maxX - other.minX; + if (d2 > offsetX) { + offsetX = d2; + } + } + return offsetX; + } + return offsetX; + } + + public double calculateYOffset(final AxisAlignedBB other, double offsetY) { + if (other.maxX > this.minX && other.minX < this.maxX && other.maxZ > this.minZ && other.minZ < this.maxZ) { + if (offsetY > 0.0 && other.maxY <= this.minY) { + final double d1 = this.minY - other.maxY; + if (d1 < offsetY) { + offsetY = d1; + } + } + else if (offsetY < 0.0 && other.minY >= this.maxY) { + final double d2 = this.maxY - other.minY; + if (d2 > offsetY) { + offsetY = d2; + } + } + return offsetY; + } + return offsetY; + } + + public double calculateZOffset(final AxisAlignedBB other, double offsetZ) { + if (other.maxX > this.minX && other.minX < this.maxX && other.maxY > this.minY && other.minY < this.maxY) { + if (offsetZ > 0.0 && other.maxZ <= this.minZ) { + final double d1 = this.minZ - other.maxZ; + if (d1 < offsetZ) { + offsetZ = d1; + } + } + else if (offsetZ < 0.0 && other.minZ >= this.maxZ) { + final double d2 = this.maxZ - other.minZ; + if (d2 > offsetZ) { + offsetZ = d2; + } + } + return offsetZ; + } + return offsetZ; + } + + public boolean intersectsWith(final AxisAlignedBB other) { + return other.maxX > this.minX && other.minX < this.maxX && (other.maxY > this.minY && other.minY < this.maxY) && (other.maxZ > this.minZ && other.minZ < this.maxZ); + } + + public boolean isVecInside(final Vec3 vec) { + return vec.xCoord > this.minX && vec.xCoord < this.maxX && (vec.yCoord > this.minY && vec.yCoord < this.maxY) && (vec.zCoord > this.minZ && vec.zCoord < this.maxZ); + } + + public double getAverageEdgeLength() { + final double d0 = this.maxX - this.minX; + final double d2 = this.maxY - this.minY; + final double d3 = this.maxZ - this.minZ; + return (d0 + d2 + d3) / 3.0; + } + + public AxisAlignedBB contract(final double x, final double y, final double z) { + final double d0 = this.minX + x; + final double d2 = this.minY + y; + final double d3 = this.minZ + z; + final double d4 = this.maxX - x; + final double d5 = this.maxY - y; + final double d6 = this.maxZ - z; + return new AxisAlignedBB(d0, d2, d3, d4, d5, d6); + } + + public MovingObjectPosition calculateIntercept(final Vec3 vecA, final Vec3 vecB) { + Vec3 vec3 = vecA.getIntermediateWithXValue(vecB, this.minX); + Vec3 vec4 = vecA.getIntermediateWithXValue(vecB, this.maxX); + Vec3 vec5 = vecA.getIntermediateWithYValue(vecB, this.minY); + Vec3 vec6 = vecA.getIntermediateWithYValue(vecB, this.maxY); + Vec3 vec7 = vecA.getIntermediateWithZValue(vecB, this.minZ); + Vec3 vec8 = vecA.getIntermediateWithZValue(vecB, this.maxZ); + if (!this.isVecInYZ(vec3)) { + vec3 = null; + } + if (!this.isVecInYZ(vec4)) { + vec4 = null; + } + if (!this.isVecInXZ(vec5)) { + vec5 = null; + } + if (!this.isVecInXZ(vec6)) { + vec6 = null; + } + if (!this.isVecInXY(vec7)) { + vec7 = null; + } + if (!this.isVecInXY(vec8)) { + vec8 = null; + } + Vec3 vec9 = null; + if (vec3 != null) { + vec9 = vec3; + } + if (vec4 != null && (vec9 == null || vecA.squareDistanceTo(vec4) < vecA.squareDistanceTo(vec9))) { + vec9 = vec4; + } + if (vec5 != null && (vec9 == null || vecA.squareDistanceTo(vec5) < vecA.squareDistanceTo(vec9))) { + vec9 = vec5; + } + if (vec6 != null && (vec9 == null || vecA.squareDistanceTo(vec6) < vecA.squareDistanceTo(vec9))) { + vec9 = vec6; + } + if (vec7 != null && (vec9 == null || vecA.squareDistanceTo(vec7) < vecA.squareDistanceTo(vec9))) { + vec9 = vec7; + } + if (vec8 != null && (vec9 == null || vecA.squareDistanceTo(vec8) < vecA.squareDistanceTo(vec9))) { + vec9 = vec8; + } + if (vec9 == null) { + return null; + } + EnumFacing enumfacing = null; + if (vec9 == vec3) { + enumfacing = EnumFacing.WEST; + } + else if (vec9 == vec4) { + enumfacing = EnumFacing.EAST; + } + else if (vec9 == vec5) { + enumfacing = EnumFacing.DOWN; + } + else if (vec9 == vec6) { + enumfacing = EnumFacing.UP; + } + else if (vec9 == vec7) { + enumfacing = EnumFacing.NORTH; + } + else { + enumfacing = EnumFacing.SOUTH; + } + return new MovingObjectPosition(vec9, enumfacing); + } + + private boolean isVecInYZ(final Vec3 vec) { + return vec != null && (vec.yCoord >= this.minY && vec.yCoord <= this.maxY && vec.zCoord >= this.minZ && vec.zCoord <= this.maxZ); + } + + private boolean isVecInXZ(final Vec3 vec) { + return vec != null && (vec.xCoord >= this.minX && vec.xCoord <= this.maxX && vec.zCoord >= this.minZ && vec.zCoord <= this.maxZ); + } + + private boolean isVecInXY(final Vec3 vec) { + return vec != null && (vec.xCoord >= this.minX && vec.xCoord <= this.maxX && vec.yCoord >= this.minY && vec.yCoord <= this.maxY); + } + + @Override + public String toString() { + return "box[" + this.minX + ", " + this.minY + ", " + this.minZ + " -> " + this.maxX + ", " + this.maxY + ", " + this.maxZ + "]"; + } + + public boolean func_181656_b() { + return Double.isNaN(this.minX) || Double.isNaN(this.minY) || Double.isNaN(this.minZ) || Double.isNaN(this.maxX) || Double.isNaN(this.maxY) || Double.isNaN(this.maxZ); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/nms/BlockPos.java b/src/main/java/me/frep/vulcan/spigot/util/nms/BlockPos.java new file mode 100644 index 0000000..427a707 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/nms/BlockPos.java @@ -0,0 +1,293 @@ +package me.frep.vulcan.spigot.util.nms; + +import com.google.common.collect.AbstractIterator; +import java.util.Iterator; +import org.bukkit.entity.Entity; + +public class BlockPos extends Vec3i +{ + public static final BlockPos ORIGIN; + private static final int field_177990_b; + private static final int field_177991_c; + private static final int field_177989_d; + private static final int field_177987_f; + private static final int field_177988_g; + private static final long field_177994_h; + private static final long field_177995_i; + private static final long field_177993_j; + private static final String __OBFID = "CL_00002334"; + + public BlockPos(final int x, final int y, final int z) { + super(x, y, z); + } + + public BlockPos(final double x, final double y, final double z) { + super(x, y, z); + } + + public BlockPos(final Entity p_i46032_1_) { + this(p_i46032_1_.getLocation().getX(), p_i46032_1_.getLocation().getY(), p_i46032_1_.getLocation().getZ()); + } + + public BlockPos(final Vec3 p_i46033_1_) { + this(p_i46033_1_.xCoord, p_i46033_1_.yCoord, p_i46033_1_.zCoord); + } + + public BlockPos(final Vec3i p_i46034_1_) { + this(p_i46034_1_.getX(), p_i46034_1_.getY(), p_i46034_1_.getZ()); + } + + public BlockPos add(final double x, final double y, final double z) { + return new BlockPos(this.getX() + x, this.getY() + y, this.getZ() + z); + } + + public BlockPos add(final int x, final int y, final int z) { + return new BlockPos(this.getX() + x, this.getY() + y, this.getZ() + z); + } + + public BlockPos add(final Vec3i vec) { + return new BlockPos(this.getX() + vec.getX(), this.getY() + vec.getY(), this.getZ() + vec.getZ()); + } + + public BlockPos subtract(final Vec3i vec) { + return new BlockPos(this.getX() - vec.getX(), this.getY() - vec.getY(), this.getZ() - vec.getZ()); + } + + public BlockPos multiply(final int factor) { + return new BlockPos(this.getX() * factor, this.getY() * factor, this.getZ() * factor); + } + + public BlockPos offsetUp() { + return this.offsetUp(1); + } + + public static String spigot() { + return "%%__USER__%%"; + } + + public static String nonce() { + return "%%__NONCE__%%"; + } + + public static String resource() { + return "%%__RESOURCE__%%"; + } + + public BlockPos offsetUp(final int n) { + return this.offset(EnumFacing.UP, n); + } + + public BlockPos offsetDown() { + return this.offsetDown(1); + } + + public BlockPos offsetDown(final int n) { + return this.offset(EnumFacing.DOWN, n); + } + + public BlockPos offsetNorth() { + return this.offsetNorth(1); + } + + public BlockPos offsetNorth(final int n) { + return this.offset(EnumFacing.NORTH, n); + } + + public BlockPos offsetSouth() { + return this.offsetSouth(1); + } + + public BlockPos offsetSouth(final int n) { + return this.offset(EnumFacing.SOUTH, n); + } + + public BlockPos offsetWest() { + return this.offsetWest(1); + } + + public BlockPos offsetWest(final int n) { + return this.offset(EnumFacing.WEST, n); + } + + public BlockPos offsetEast() { + return this.offsetEast(1); + } + + public BlockPos offsetEast(final int n) { + return this.offset(EnumFacing.EAST, n); + } + + public BlockPos offset(final EnumFacing facing) { + return this.offset(facing, 1); + } + + public BlockPos offset(final EnumFacing facing, final int n) { + return new BlockPos(this.getX() + facing.getFrontOffsetX() * n, this.getY() + facing.getFrontOffsetY() * n, this.getZ() + facing.getFrontOffsetZ() * n); + } + + public BlockPos crossProductBP(final Vec3i vec) { + return new BlockPos(this.getY() * vec.getZ() - this.getZ() * vec.getY(), this.getZ() * vec.getX() - this.getX() * vec.getZ(), this.getX() * vec.getY() - this.getY() * vec.getX()); + } + + public long toLong() { + return ((long)this.getX() & BlockPos.field_177994_h) << BlockPos.field_177988_g | ((long)this.getY() & BlockPos.field_177995_i) << BlockPos.field_177987_f | ((long)this.getZ() & BlockPos.field_177993_j) << 0; + } + + public static BlockPos fromLong(final long serialized) { + final int var2 = (int)(serialized << 64 - BlockPos.field_177988_g - BlockPos.field_177990_b >> 64 - BlockPos.field_177990_b); + final int var3 = (int)(serialized << 64 - BlockPos.field_177987_f - BlockPos.field_177989_d >> 64 - BlockPos.field_177989_d); + final int var4 = (int)(serialized << 64 - BlockPos.field_177991_c >> 64 - BlockPos.field_177991_c); + return new BlockPos(var2, var3, var4); + } + + public static Iterable getAllInBox(final BlockPos from, final BlockPos to) { + final BlockPos var2 = new BlockPos(Math.min(from.getX(), to.getX()), Math.min(from.getY(), to.getY()), Math.min(from.getZ(), to.getZ())); + final BlockPos var3 = new BlockPos(Math.max(from.getX(), to.getX()), Math.max(from.getY(), to.getY()), Math.max(from.getZ(), to.getZ())); + return new Iterable() { + private static final String __OBFID = "CL_00002333"; + + @Override + public Iterator iterator() { + return new AbstractIterator() { + private BlockPos lastReturned = null; + private static final String __OBFID = "CL_00002332"; + + protected BlockPos computeNext0() { + if (this.lastReturned == null) { + return this.lastReturned = var2; + } + if (this.lastReturned.equals(var3)) { + return (BlockPos) this.endOfData(); + } + int var1 = this.lastReturned.getX(); + int var2x = this.lastReturned.getY(); + int var3x = this.lastReturned.getZ(); + if (var1 < var3.getX()) { + ++var1; + } + else if (var2x < var3.getY()) { + var1 = var2.getX(); + ++var2x; + } + else if (var3x < var3.getZ()) { + var1 = var2.getX(); + var2x = var2.getY(); + ++var3x; + } + return this.lastReturned = new BlockPos(var1, var2x, var3x); + } + + @Override + protected Object computeNext() { + return this.computeNext0(); + } + }; + } + }; + } + + public static Iterable getAllInBoxMutable(final BlockPos from, final BlockPos to) { + final BlockPos var2 = new BlockPos(Math.min(from.getX(), to.getX()), Math.min(from.getY(), to.getY()), Math.min(from.getZ(), to.getZ())); + final BlockPos var3 = new BlockPos(Math.max(from.getX(), to.getX()), Math.max(from.getY(), to.getY()), Math.max(from.getZ(), to.getZ())); + return new Iterable() { + private static final String __OBFID = "CL_00002331"; + + @Override + public Iterator iterator() { + return new AbstractIterator() { + private MutableBlockPos theBlockPos = null; + private static final String __OBFID = "CL_00002330"; + + protected MutableBlockPos computeNext0() { + if (this.theBlockPos == null) { + return this.theBlockPos = new MutableBlockPos(var2.getX(), var2.getY(), var2.getZ(), null); + } + if (this.theBlockPos.equals(var3)) { + return (MutableBlockPos) this.endOfData(); + } + int var1 = this.theBlockPos.getX(); + int var2xx = this.theBlockPos.getY(); + int var3x = this.theBlockPos.getZ(); + if (var1 < var3.getX()) { + ++var1; + } + else if (var2xx < var3.getY()) { + var1 = var2.getX(); + ++var2xx; + } + else if (var3x < var3.getZ()) { + var1 = var2.getX(); + var2xx = var2.getY(); + ++var3x; + } + this.theBlockPos.x = var1; + this.theBlockPos.y = var2xx; + this.theBlockPos.z = var3x; + return this.theBlockPos; + } + + @Override + protected Object computeNext() { + return this.computeNext0(); + } + }; + } + }; + } + + @Override + public Vec3i crossProduct(final Vec3i vec) { + return this.crossProductBP(vec); + } + + static { + ORIGIN = new BlockPos(0, 0, 0); + field_177990_b = 1 + MathHelper.calculateLogBaseTwo(MathHelper.roundUpToPowerOfTwo(30000000)); + field_177991_c = BlockPos.field_177990_b; + field_177989_d = 64 - BlockPos.field_177990_b - BlockPos.field_177991_c; + field_177987_f = 0 + BlockPos.field_177991_c; + field_177988_g = BlockPos.field_177987_f + BlockPos.field_177989_d; + field_177994_h = (1L << BlockPos.field_177990_b) - 1L; + field_177995_i = (1L << BlockPos.field_177989_d) - 1L; + field_177993_j = (1L << BlockPos.field_177991_c) - 1L; + } + + public static final class MutableBlockPos extends BlockPos + { + public int x; + public int y; + public int z; + private static final String __OBFID = "CL_00002329"; + + private MutableBlockPos(final int x_, final int y_, final int z_) { + super(0, 0, 0); + this.x = x_; + this.y = y_; + this.z = z_; + } + + @Override + public int getX() { + return this.x; + } + + @Override + public int getY() { + return this.y; + } + + @Override + public int getZ() { + return this.z; + } + + @Override + public Vec3i crossProduct(final Vec3i vec) { + return super.crossProductBP(vec); + } + + MutableBlockPos(final int p_i46025_1_, final int p_i46025_2_, final int p_i46025_3_, final Object p_i46025_4_) { + this(p_i46025_1_, p_i46025_2_, p_i46025_3_); + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/nms/EnumFacing.java b/src/main/java/me/frep/vulcan/spigot/util/nms/EnumFacing.java new file mode 100644 index 0000000..7f84157 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/nms/EnumFacing.java @@ -0,0 +1,443 @@ +package me.frep.vulcan.spigot.util.nms; + +import com.google.common.collect.Iterators; +import java.util.Iterator; +import com.google.common.base.Predicate; +import com.google.common.collect.Maps; +import java.util.Random; +import java.util.Map; + +public enum EnumFacing implements IStringSerializable +{ + DOWN(0, 1, -1, "down", AxisDirection.NEGATIVE, Axis.Y, new Vec3i(0, -1, 0)), + UP(1, 0, -1, "up", AxisDirection.POSITIVE, Axis.Y, new Vec3i(0, 1, 0)), + NORTH(2, 3, 2, "north", AxisDirection.NEGATIVE, Axis.Z, new Vec3i(0, 0, -1)), + SOUTH(3, 2, 0, "south", AxisDirection.POSITIVE, Axis.Z, new Vec3i(0, 0, 1)), + WEST(4, 5, 1, "west", AxisDirection.NEGATIVE, Axis.X, new Vec3i(-1, 0, 0)), + EAST(5, 4, 3, "east", AxisDirection.POSITIVE, Axis.X, new Vec3i(1, 0, 0)); + + private final int index; + private final int opposite; + private final int horizontalIndex; + private final String name; + private final Axis axis; + private final AxisDirection axisDirection; + private final Vec3i directionVec; + private static final EnumFacing[] VALUES; + private static final EnumFacing[] HORIZONTALS; + private static final Map NAME_LOOKUP; + private static final String __OBFID = "CL_00001201"; + + private EnumFacing(final int p_i46016_3_, final int p_i46016_4_, final int p_i46016_5_, final String p_i46016_6_, final AxisDirection p_i46016_7_, final Axis p_i46016_8_, final Vec3i p_i46016_9_) { + this.index = p_i46016_3_; + this.horizontalIndex = p_i46016_5_; + this.opposite = p_i46016_4_; + this.name = p_i46016_6_; + this.axis = p_i46016_8_; + this.axisDirection = p_i46016_7_; + this.directionVec = p_i46016_9_; + } + + public int getIndex() { + return this.index; + } + + public int getHorizontalIndex() { + return this.horizontalIndex; + } + + public AxisDirection getAxisDirection() { + return this.axisDirection; + } + + public EnumFacing getOpposite() { + return getFront(this.opposite); + } + + public EnumFacing rotateAround(final Axis axis) { + switch (SwitchPlane.AXIS_LOOKUP[axis.ordinal()]) { + case 1: { + if (this != EnumFacing.WEST && this != EnumFacing.EAST) { + return this.rotateX(); + } + return this; + } + case 2: { + if (this != EnumFacing.UP && this != EnumFacing.DOWN) { + return this.rotateY(); + } + return this; + } + case 3: { + if (this != EnumFacing.NORTH && this != EnumFacing.SOUTH) { + return this.rotateZ(); + } + return this; + } + default: { + throw new IllegalStateException("Unable to get CW facing for axis " + axis); + } + } + } + + public EnumFacing rotateY() { + switch (SwitchPlane.FACING_LOOKUP[this.ordinal()]) { + case 1: { + return EnumFacing.EAST; + } + case 2: { + return EnumFacing.SOUTH; + } + case 3: { + return EnumFacing.WEST; + } + case 4: { + return EnumFacing.NORTH; + } + default: { + throw new IllegalStateException("Unable to get Y-rotated facing of " + this); + } + } + } + + private EnumFacing rotateX() { + switch (SwitchPlane.FACING_LOOKUP[this.ordinal()]) { + case 1: { + return EnumFacing.DOWN; + } + default: { + throw new IllegalStateException("Unable to get X-rotated facing of " + this); + } + case 3: { + return EnumFacing.UP; + } + case 5: { + return EnumFacing.NORTH; + } + case 6: { + return EnumFacing.SOUTH; + } + } + } + + private EnumFacing rotateZ() { + switch (SwitchPlane.FACING_LOOKUP[this.ordinal()]) { + case 2: { + return EnumFacing.DOWN; + } + default: { + throw new IllegalStateException("Unable to get Z-rotated facing of " + this); + } + case 4: { + return EnumFacing.UP; + } + case 5: { + return EnumFacing.EAST; + } + case 6: { + return EnumFacing.WEST; + } + } + } + + public EnumFacing rotateYCCW() { + switch (SwitchPlane.FACING_LOOKUP[this.ordinal()]) { + case 1: { + return EnumFacing.WEST; + } + case 2: { + return EnumFacing.NORTH; + } + case 3: { + return EnumFacing.EAST; + } + case 4: { + return EnumFacing.SOUTH; + } + default: { + throw new IllegalStateException("Unable to get CCW facing of " + this); + } + } + } + + public int getFrontOffsetX() { + return (this.axis == Axis.X) ? this.axisDirection.getOffset() : 0; + } + + public int getFrontOffsetY() { + return (this.axis == Axis.Y) ? this.axisDirection.getOffset() : 0; + } + + public int getFrontOffsetZ() { + return (this.axis == Axis.Z) ? this.axisDirection.getOffset() : 0; + } + + public String getName2() { + return this.name; + } + + public Axis getAxis() { + return this.axis; + } + + public static EnumFacing byName(final String name) { + return (name == null) ? null : (EnumFacing) EnumFacing.NAME_LOOKUP.get(name.toLowerCase()); + } + + public static EnumFacing getFront(final int index) { + return EnumFacing.VALUES[MathHelper.abs_int(index % EnumFacing.VALUES.length)]; + } + + public static EnumFacing getHorizontal(final int p_176731_0_) { + return EnumFacing.HORIZONTALS[MathHelper.abs_int(p_176731_0_ % EnumFacing.HORIZONTALS.length)]; + } + + public static EnumFacing fromAngle(final double angle) { + return getHorizontal(MathHelper.floor_double(angle / 90.0 + 0.5) & 0x3); + } + + public static EnumFacing random(final Random rand) { + return values()[rand.nextInt(values().length)]; + } + + public static EnumFacing func_176737_a(final float p_176737_0_, final float p_176737_1_, final float p_176737_2_) { + EnumFacing var3 = EnumFacing.NORTH; + float var4 = Float.MIN_VALUE; + for (final EnumFacing var8 : values()) { + final float var9 = p_176737_0_ * var8.directionVec.getX() + p_176737_1_ * var8.directionVec.getY() + p_176737_2_ * var8.directionVec.getZ(); + if (var9 > var4) { + var4 = var9; + var3 = var8; + } + } + return var3; + } + + @Override + public String toString() { + return this.name; + } + + @Override + public String getName() { + return this.name; + } + + public Vec3i getDirectionVec() { + return this.directionVec; + } + + static { + VALUES = new EnumFacing[6]; + HORIZONTALS = new EnumFacing[4]; + NAME_LOOKUP = Maps.newHashMap(); + for (final EnumFacing var4 : values()) { + EnumFacing.VALUES[var4.index] = var4; + if (var4.getAxis().isHorizontal()) { + EnumFacing.HORIZONTALS[var4.horizontalIndex] = var4; + } + EnumFacing.NAME_LOOKUP.put(var4.getName2().toLowerCase(), var4); + } + } + + public enum Axis implements Predicate, IStringSerializable + { + X("X", 0, "x", Plane.HORIZONTAL), + Y("Y", 1, "y", Plane.VERTICAL), + Z("Z", 2, "z", Plane.HORIZONTAL); + + private static final Map NAME_LOOKUP; + private final String name; + private final Plane plane; + private static final Axis[] $VALUES; + private static final String __OBFID = "CL_00002321"; + + private Axis(final String p_i46015_1_, final int p_i46015_2_, final String name, final Plane plane) { + this.name = name; + this.plane = plane; + } + + public static Axis byName(final String name) { + return (name == null) ? null : (Axis) Axis.NAME_LOOKUP.get(name.toLowerCase()); + } + + public String getName2() { + return this.name; + } + + public boolean isVertical() { + return this.plane == Plane.VERTICAL; + } + + public boolean isHorizontal() { + return this.plane == Plane.HORIZONTAL; + } + + @Override + public String toString() { + return this.name; + } + + public boolean apply(final EnumFacing facing) { + return facing != null && facing.getAxis() == this; + } + + public Plane getPlane() { + return this.plane; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public boolean apply(final Object p_apply_1_) { + return this.apply((EnumFacing)p_apply_1_); + } + + static { + NAME_LOOKUP = Maps.newHashMap(); + $VALUES = new Axis[] { Axis.X, Axis.Y, Axis.Z }; + for (final Axis var4 : values()) { + Axis.NAME_LOOKUP.put(var4.getName2().toLowerCase(), var4); + } + } + } + + public enum AxisDirection + { + POSITIVE("POSITIVE", 0, 1, "Towards positive"), + NEGATIVE("NEGATIVE", 1, -1, "Towards negative"); + + private final int offset; + private final String description; + private static final AxisDirection[] $VALUES; + private static final String __OBFID = "CL_00002320"; + + private AxisDirection(final String p_i46014_1_, final int p_i46014_2_, final int offset, final String description) { + this.offset = offset; + this.description = description; + } + + public int getOffset() { + return this.offset; + } + + @Override + public String toString() { + return this.description; + } + + static { + $VALUES = new AxisDirection[] { AxisDirection.POSITIVE, AxisDirection.NEGATIVE }; + } + } + + public enum Plane implements Predicate, Iterable + { + HORIZONTAL("HORIZONTAL", 0), + VERTICAL("VERTICAL", 1); + + private static final Plane[] $VALUES; + private static final String __OBFID = "CL_00002319"; + + private Plane(final String p_i46013_1_, final int p_i46013_2_) { + } + + public EnumFacing[] facings() { + switch (SwitchPlane.PLANE_LOOKUP[this.ordinal()]) { + case 1: { + return new EnumFacing[] { EnumFacing.NORTH, EnumFacing.EAST, EnumFacing.SOUTH, EnumFacing.WEST }; + } + case 2: { + return new EnumFacing[] { EnumFacing.UP, EnumFacing.DOWN }; + } + default: { + throw new Error("Someone's been tampering with the universe!"); + } + } + } + + public EnumFacing random(final Random rand) { + final EnumFacing[] var2 = this.facings(); + return var2[rand.nextInt(var2.length)]; + } + + public boolean apply(final EnumFacing facing) { + return facing != null && facing.getAxis().getPlane() == this; + } + + @Override + public Iterator iterator() { + return Iterators.forArray(this.facings()); + } + + @Override + public boolean apply(final Object p_apply_1_) { + return this.apply((EnumFacing)p_apply_1_); + } + + static { + $VALUES = new Plane[] { Plane.HORIZONTAL, Plane.VERTICAL }; + } + } + + static final class SwitchPlane + { + static final int[] AXIS_LOOKUP; + static final int[] FACING_LOOKUP; + static final int[] PLANE_LOOKUP; + private static final String __OBFID = "CL_00002322"; + + static { + PLANE_LOOKUP = new int[Plane.values().length]; + try { + SwitchPlane.PLANE_LOOKUP[Plane.HORIZONTAL.ordinal()] = 1; + } + catch (final NoSuchFieldError noSuchFieldError) {} + try { + SwitchPlane.PLANE_LOOKUP[Plane.VERTICAL.ordinal()] = 2; + } + catch (final NoSuchFieldError noSuchFieldError2) {} + FACING_LOOKUP = new int[EnumFacing.values().length]; + try { + SwitchPlane.FACING_LOOKUP[EnumFacing.NORTH.ordinal()] = 1; + } + catch (final NoSuchFieldError noSuchFieldError3) {} + try { + SwitchPlane.FACING_LOOKUP[EnumFacing.EAST.ordinal()] = 2; + } + catch (final NoSuchFieldError noSuchFieldError4) {} + try { + SwitchPlane.FACING_LOOKUP[EnumFacing.SOUTH.ordinal()] = 3; + } + catch (final NoSuchFieldError noSuchFieldError5) {} + try { + SwitchPlane.FACING_LOOKUP[EnumFacing.WEST.ordinal()] = 4; + } + catch (final NoSuchFieldError noSuchFieldError6) {} + try { + SwitchPlane.FACING_LOOKUP[EnumFacing.UP.ordinal()] = 5; + } + catch (final NoSuchFieldError noSuchFieldError7) {} + try { + SwitchPlane.FACING_LOOKUP[EnumFacing.DOWN.ordinal()] = 6; + } + catch (final NoSuchFieldError noSuchFieldError8) {} + AXIS_LOOKUP = new int[Axis.values().length]; + try { + SwitchPlane.AXIS_LOOKUP[Axis.X.ordinal()] = 1; + } + catch (final NoSuchFieldError noSuchFieldError9) {} + try { + SwitchPlane.AXIS_LOOKUP[Axis.Y.ordinal()] = 2; + } + catch (final NoSuchFieldError noSuchFieldError10) {} + try { + SwitchPlane.AXIS_LOOKUP[Axis.Z.ordinal()] = 3; + } + catch (final NoSuchFieldError noSuchFieldError11) {} + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/nms/IStringSerializable.java b/src/main/java/me/frep/vulcan/spigot/util/nms/IStringSerializable.java new file mode 100644 index 0000000..c018ee5 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/nms/IStringSerializable.java @@ -0,0 +1,6 @@ +package me.frep.vulcan.spigot.util.nms; + +public interface IStringSerializable +{ + String getName(); +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/nms/MathHelper.java b/src/main/java/me/frep/vulcan/spigot/util/nms/MathHelper.java new file mode 100644 index 0000000..afd3afe --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/nms/MathHelper.java @@ -0,0 +1,274 @@ +package me.frep.vulcan.spigot.util.nms; + +import java.util.UUID; +import java.util.Random; + +public class MathHelper +{ + public static final float field_180189_a; + private static final float[] SIN_TABLE; + private static final int[] multiplyDeBruijnBitPosition; + private static final String __OBFID = "CL_00001496"; + + public static float sin(final float p_76126_0_) { + return MathHelper.SIN_TABLE[(int)(p_76126_0_ * 10430.378f) & 0xFFFF]; + } + + public static String spigot() { + return "%%__USER__%%"; + } + + public static String nonce() { + return "%%__NONCE__%%"; + } + + public static String resource() { + return "%%__RESOURCE__%%"; + } + + public static float cos(final float p_76134_0_) { + return MathHelper.SIN_TABLE[(int)(p_76134_0_ * 10430.378f + 16384.0f) & 0xFFFF]; + } + + public static float sqrt_float(final float p_76129_0_) { + return (float)Math.sqrt(p_76129_0_); + } + + public static float sqrt_double(final double p_76133_0_) { + return (float)Math.sqrt(p_76133_0_); + } + + public static int floor_float(final float p_76141_0_) { + final int var1 = (int)p_76141_0_; + return (p_76141_0_ < var1) ? (var1 - 1) : var1; + } + + public static int truncateDoubleToInt(final double p_76140_0_) { + return (int)(p_76140_0_ + 1024.0) - 1024; + } + + public static int floor_double(final double p_76128_0_) { + final int var2 = (int)p_76128_0_; + return (p_76128_0_ < var2) ? (var2 - 1) : var2; + } + + public static long floor_double_long(final double p_76124_0_) { + final long var2 = (long)p_76124_0_; + return (p_76124_0_ < var2) ? (var2 - 1L) : var2; + } + + public static int func_154353_e(final double p_154353_0_) { + return (int)((p_154353_0_ >= 0.0) ? p_154353_0_ : (-p_154353_0_ + 1.0)); + } + + public static float abs(final float p_76135_0_) { + return (p_76135_0_ >= 0.0f) ? p_76135_0_ : (-p_76135_0_); + } + + public static int abs_int(final int p_76130_0_) { + return (p_76130_0_ >= 0) ? p_76130_0_ : (-p_76130_0_); + } + + public static int ceiling_float_int(final float p_76123_0_) { + final int var1 = (int)p_76123_0_; + return (p_76123_0_ > var1) ? (var1 + 1) : var1; + } + + public static int ceiling_double_int(final double p_76143_0_) { + final int var2 = (int)p_76143_0_; + return (p_76143_0_ > var2) ? (var2 + 1) : var2; + } + + public static int clamp_int(final int p_76125_0_, final int p_76125_1_, final int p_76125_2_) { + return (p_76125_0_ < p_76125_1_) ? p_76125_1_ : ((p_76125_0_ > p_76125_2_) ? p_76125_2_ : p_76125_0_); + } + + public static float clamp_float(final float p_76131_0_, final float p_76131_1_, final float p_76131_2_) { + return (p_76131_0_ < p_76131_1_) ? p_76131_1_ : ((p_76131_0_ > p_76131_2_) ? p_76131_2_ : p_76131_0_); + } + + public static double clamp_double(final double p_151237_0_, final double p_151237_2_, final double p_151237_4_) { + return (p_151237_0_ < p_151237_2_) ? p_151237_2_ : ((p_151237_0_ > p_151237_4_) ? p_151237_4_ : p_151237_0_); + } + + public static double denormalizeClamp(final double p_151238_0_, final double p_151238_2_, final double p_151238_4_) { + return (p_151238_4_ < 0.0) ? p_151238_0_ : ((p_151238_4_ > 1.0) ? p_151238_2_ : (p_151238_0_ + (p_151238_2_ - p_151238_0_) * p_151238_4_)); + } + + public static double abs_max(double p_76132_0_, double p_76132_2_) { + if (p_76132_0_ < 0.0) { + p_76132_0_ = -p_76132_0_; + } + if (p_76132_2_ < 0.0) { + p_76132_2_ = -p_76132_2_; + } + return (p_76132_0_ > p_76132_2_) ? p_76132_0_ : p_76132_2_; + } + + public static int bucketInt(final int p_76137_0_, final int p_76137_1_) { + return (p_76137_0_ < 0) ? (-((-p_76137_0_ - 1) / p_76137_1_) - 1) : (p_76137_0_ / p_76137_1_); + } + + public static int getRandomIntegerInRange(final Random p_76136_0_, final int p_76136_1_, final int p_76136_2_) { + return (p_76136_1_ >= p_76136_2_) ? p_76136_1_ : (p_76136_0_.nextInt(p_76136_2_ - p_76136_1_ + 1) + p_76136_1_); + } + + public static float randomFloatClamp(final Random p_151240_0_, final float p_151240_1_, final float p_151240_2_) { + return (p_151240_1_ >= p_151240_2_) ? p_151240_1_ : (p_151240_0_.nextFloat() * (p_151240_2_ - p_151240_1_) + p_151240_1_); + } + + public static double getRandomDoubleInRange(final Random p_82716_0_, final double p_82716_1_, final double p_82716_3_) { + return (p_82716_1_ >= p_82716_3_) ? p_82716_1_ : (p_82716_0_.nextDouble() * (p_82716_3_ - p_82716_1_) + p_82716_1_); + } + + public static double average(final long[] p_76127_0_) { + long var1 = 0L; + final long[] var2 = p_76127_0_; + for (int var3 = p_76127_0_.length, var4 = 0; var4 < var3; ++var4) { + final long var5 = var2[var4]; + var1 += var5; + } + return var1 / (double)p_76127_0_.length; + } + + public static boolean func_180185_a(final float p_180185_0_, final float p_180185_1_) { + return abs(p_180185_1_ - p_180185_0_) < 1.0E-5f; + } + + public static int func_180184_b(final int p_180184_0_, final int p_180184_1_) { + return (p_180184_0_ % p_180184_1_ + p_180184_1_) % p_180184_1_; + } + + public static float wrapAngleTo180_float(float yaw) { + yaw %= 360.0f; + if (yaw >= 180.0f) { + yaw -= 360.0f; + } + if (yaw < -180.0f) { + yaw += 360.0f; + } + return yaw; + } + + public static double wrapAngleTo180_double(double p_76138_0_) { + p_76138_0_ %= 360.0; + if (p_76138_0_ >= 180.0) { + p_76138_0_ -= 360.0; + } + if (p_76138_0_ < -180.0) { + p_76138_0_ += 360.0; + } + return p_76138_0_; + } + + public static int parseIntWithDefault(final String p_82715_0_, final int p_82715_1_) { + try { + return Integer.parseInt(p_82715_0_); + } + catch (final Throwable var3) { + return p_82715_1_; + } + } + + public static int parseIntWithDefaultAndMax(final String p_82714_0_, final int p_82714_1_, final int p_82714_2_) { + return Math.max(p_82714_2_, parseIntWithDefault(p_82714_0_, p_82714_1_)); + } + + public static double parseDoubleWithDefault(final String p_82712_0_, final double p_82712_1_) { + try { + return Double.parseDouble(p_82712_0_); + } + catch (final Throwable var4) { + return p_82712_1_; + } + } + + public static double parseDoubleWithDefaultAndMax(final String p_82713_0_, final double p_82713_1_, final double p_82713_3_) { + return Math.max(p_82713_3_, parseDoubleWithDefault(p_82713_0_, p_82713_1_)); + } + + public static int roundUpToPowerOfTwo(final int p_151236_0_) { + int var1 = p_151236_0_ - 1; + var1 |= var1 >> 1; + var1 |= var1 >> 2; + var1 |= var1 >> 4; + var1 |= var1 >> 8; + var1 |= var1 >> 16; + return var1 + 1; + } + + private static boolean isPowerOfTwo(final int p_151235_0_) { + return p_151235_0_ != 0 && (p_151235_0_ & p_151235_0_ - 1) == 0x0; + } + + private static int calculateLogBaseTwoDeBruijn(int p_151241_0_) { + p_151241_0_ = (isPowerOfTwo(p_151241_0_) ? p_151241_0_ : roundUpToPowerOfTwo(p_151241_0_)); + return MathHelper.multiplyDeBruijnBitPosition[(int)(p_151241_0_ * 125613361L >> 27) & 0x1F]; + } + + public static int calculateLogBaseTwo(final int p_151239_0_) { + return calculateLogBaseTwoDeBruijn(p_151239_0_) - (isPowerOfTwo(p_151239_0_) ? 0 : 1); + } + + public static int func_154354_b(final int p_154354_0_, int p_154354_1_) { + if (p_154354_1_ == 0) { + return 0; + } + if (p_154354_0_ == 0) { + return p_154354_1_; + } + if (p_154354_0_ < 0) { + p_154354_1_ *= -1; + } + final int var2 = p_154354_0_ % p_154354_1_; + return (var2 == 0) ? p_154354_0_ : (p_154354_0_ + p_154354_1_ - var2); + } + + public static int func_180183_b(final float p_180183_0_, final float p_180183_1_, final float p_180183_2_) { + return func_180181_b(floor_float(p_180183_0_ * 255.0f), floor_float(p_180183_1_ * 255.0f), floor_float(p_180183_2_ * 255.0f)); + } + + public static int func_180181_b(final int p_180181_0_, final int p_180181_1_, final int p_180181_2_) { + int var3 = (p_180181_0_ << 8) + p_180181_1_; + var3 = (var3 << 8) + p_180181_2_; + return var3; + } + + public static int func_180188_d(final int p_180188_0_, final int p_180188_1_) { + final int var2 = (p_180188_0_ & 0xFF0000) >> 16; + final int var3 = (p_180188_1_ & 0xFF0000) >> 16; + final int var4 = (p_180188_0_ & 0xFF00) >> 8; + final int var5 = (p_180188_1_ & 0xFF00) >> 8; + final int var6 = (p_180188_0_ & 0xFF) >> 0; + final int var7 = (p_180188_1_ & 0xFF) >> 0; + final int var8 = (int)(var2 * (float)var3 / 255.0f); + final int var9 = (int)(var4 * (float)var5 / 255.0f); + final int var10 = (int)(var6 * (float)var7 / 255.0f); + return (p_180188_0_ & 0xFF000000) | var8 << 16 | var9 << 8 | var10; + } + + public static long func_180186_a(final Vec3i p_180186_0_) { + return func_180187_c(p_180186_0_.getX(), p_180186_0_.getY(), p_180186_0_.getZ()); + } + + public static long func_180187_c(final int p_180187_0_, final int p_180187_1_, final int p_180187_2_) { + long var3 = (long)(p_180187_0_ * 3129871) ^ p_180187_2_ * 116129781L ^ (long)p_180187_1_; + var3 = var3 * var3 * 42317861L + var3 * 11L; + return var3; + } + + public static UUID func_180182_a(final Random p_180182_0_) { + final long var1 = (p_180182_0_.nextLong() & 0xFFFFFFFFFFFF0FFFL) | 0x4000L; + final long var2 = (p_180182_0_.nextLong() & 0x3FFFFFFFFFFFFFFFL) | Long.MIN_VALUE; + return new UUID(var1, var2); + } + + static { + field_180189_a = sqrt_float(2.0f); + SIN_TABLE = new float[65536]; + for (int var0 = 0; var0 < 65536; ++var0) { + MathHelper.SIN_TABLE[var0] = (float)Math.sin(var0 * 3.141592653589793 * 2.0 / 65536.0); + } + multiplyDeBruijnBitPosition = new int[] { 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 }; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/nms/MovingObjectPosition.java b/src/main/java/me/frep/vulcan/spigot/util/nms/MovingObjectPosition.java new file mode 100644 index 0000000..99458af --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/nms/MovingObjectPosition.java @@ -0,0 +1,53 @@ +package me.frep.vulcan.spigot.util.nms; + +import org.bukkit.entity.Entity; + +public class MovingObjectPosition +{ + private BlockPos blockPos; + public MovingObjectType typeOfHit; + public EnumFacing sideHit; + public Vec3 hitVec; + public Entity entityHit; + + public MovingObjectPosition(final Vec3 hitVecIn, final EnumFacing facing, final BlockPos blockPosIn) { + this(MovingObjectType.BLOCK, hitVecIn, facing, blockPosIn); + } + + public MovingObjectPosition(final Vec3 p_i45552_1_, final EnumFacing facing) { + this(MovingObjectType.BLOCK, p_i45552_1_, facing, BlockPos.ORIGIN); + } + + public MovingObjectPosition(final Entity p_i2304_1_) { + this(p_i2304_1_, new Vec3(p_i2304_1_.getLocation().getX(), p_i2304_1_.getLocation().getY(), p_i2304_1_.getLocation().getZ())); + } + + public MovingObjectPosition(final MovingObjectType typeOfHitIn, final Vec3 hitVecIn, final EnumFacing sideHitIn, final BlockPos blockPosIn) { + this.typeOfHit = typeOfHitIn; + this.blockPos = blockPosIn; + this.sideHit = sideHitIn; + this.hitVec = new Vec3(hitVecIn.xCoord, hitVecIn.yCoord, hitVecIn.zCoord); + } + + public MovingObjectPosition(final Entity entityHitIn, final Vec3 hitVecIn) { + this.typeOfHit = MovingObjectType.ENTITY; + this.entityHit = entityHitIn; + this.hitVec = hitVecIn; + } + + public BlockPos getBlockPos() { + return this.blockPos; + } + + @Override + public String toString() { + return "HitResult{type=" + this.typeOfHit + ", blockpos=" + this.blockPos + ", f=" + this.sideHit + ", pos=" + this.hitVec + ", entity=" + this.entityHit + '}'; + } + + public enum MovingObjectType + { + MISS, + BLOCK, + ENTITY; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/nms/Vec3.java b/src/main/java/me/frep/vulcan/spigot/util/nms/Vec3.java new file mode 100644 index 0000000..ae75097 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/nms/Vec3.java @@ -0,0 +1,155 @@ +package me.frep.vulcan.spigot.util.nms; + +public class Vec3 +{ + public final double xCoord; + public final double yCoord; + public final double zCoord; + private static final String __OBFID = "CL_00000612"; + + public static String spigot() { + return "%%__USER__%%"; + } + + public static String nonce() { + return "%%__NONCE__%%"; + } + + public static String resource() { + return "%%__RESOURCE__%%"; + } + + public Vec3(double x, double y, double z) { + if (x == -0.0) { + x = 0.0; + } + if (y == -0.0) { + y = 0.0; + } + if (z == -0.0) { + z = 0.0; + } + this.xCoord = x; + this.yCoord = y; + this.zCoord = z; + } + + public Vec3 subtractReverse(final Vec3 vec) { + return new Vec3(vec.xCoord - this.xCoord, vec.yCoord - this.yCoord, vec.zCoord - this.zCoord); + } + + public Vec3 normalize() { + final double var1 = MathHelper.sqrt_double(this.xCoord * this.xCoord + this.yCoord * this.yCoord + this.zCoord * this.zCoord); + return (var1 < 1.0E-4) ? new Vec3(0.0, 0.0, 0.0) : new Vec3(this.xCoord / var1, this.yCoord / var1, this.zCoord / var1); + } + + public double dotProduct(final Vec3 vec) { + return this.xCoord * vec.xCoord + this.yCoord * vec.yCoord + this.zCoord * vec.zCoord; + } + + public Vec3 crossProduct(final Vec3 vec) { + return new Vec3(this.yCoord * vec.zCoord - this.zCoord * vec.yCoord, this.zCoord * vec.xCoord - this.xCoord * vec.zCoord, this.xCoord * vec.yCoord - this.yCoord * vec.xCoord); + } + + public Vec3 subtract(final Vec3 p_178788_1_) { + return this.subtract(p_178788_1_.xCoord, p_178788_1_.yCoord, p_178788_1_.zCoord); + } + + public Vec3 subtract(final double p_178786_1_, final double p_178786_3_, final double p_178786_5_) { + return this.addVector(-p_178786_1_, -p_178786_3_, -p_178786_5_); + } + + public Vec3 add(final Vec3 p_178787_1_) { + return this.addVector(p_178787_1_.xCoord, p_178787_1_.yCoord, p_178787_1_.zCoord); + } + + public Vec3 addVector(final double x, final double y, final double z) { + return new Vec3(this.xCoord + x, this.yCoord + y, this.zCoord + z); + } + + public double distanceTo(final Vec3 vec) { + final double var2 = vec.xCoord - this.xCoord; + final double var3 = vec.yCoord - this.yCoord; + final double var4 = vec.zCoord - this.zCoord; + return MathHelper.sqrt_double(var2 * var2 + var3 * var3 + var4 * var4); + } + + public double squareDistanceTo(final Vec3 vec) { + final double var2 = vec.xCoord - this.xCoord; + final double var3 = vec.yCoord - this.yCoord; + final double var4 = vec.zCoord - this.zCoord; + return var2 * var2 + var3 * var3 + var4 * var4; + } + + public double lengthVector() { + return MathHelper.sqrt_double(this.xCoord * this.xCoord + this.yCoord * this.yCoord + this.zCoord * this.zCoord); + } + + public Vec3 getIntermediateWithXValue(final Vec3 vec, final double x) { + final double var4 = vec.xCoord - this.xCoord; + final double var5 = vec.yCoord - this.yCoord; + final double var6 = vec.zCoord - this.zCoord; + if (var4 * var4 < 1.0000000116860974E-7) { + return null; + } + final double var7 = (x - this.xCoord) / var4; + return (var7 >= 0.0 && var7 <= 1.0) ? new Vec3(this.xCoord + var4 * var7, this.yCoord + var5 * var7, this.zCoord + var6 * var7) : null; + } + + public Vec3 getIntermediateWithYValue(final Vec3 vec, final double y) { + final double var4 = vec.xCoord - this.xCoord; + final double var5 = vec.yCoord - this.yCoord; + final double var6 = vec.zCoord - this.zCoord; + if (var5 * var5 < 1.0000000116860974E-7) { + return null; + } + final double var7 = (y - this.yCoord) / var5; + return (var7 >= 0.0 && var7 <= 1.0) ? new Vec3(this.xCoord + var4 * var7, this.yCoord + var5 * var7, this.zCoord + var6 * var7) : null; + } + + public Vec3 getIntermediateWithZValue(final Vec3 vec, final double z) { + final double var4 = vec.xCoord - this.xCoord; + final double var5 = vec.yCoord - this.yCoord; + final double var6 = vec.zCoord - this.zCoord; + if (var6 * var6 < 1.0000000116860974E-7) { + return null; + } + final double var7 = (z - this.zCoord) / var6; + return (var7 >= 0.0 && var7 <= 1.0) ? new Vec3(this.xCoord + var4 * var7, this.yCoord + var5 * var7, this.zCoord + var6 * var7) : null; + } + + @Override + public String toString() { + return "(" + this.xCoord + ", " + this.yCoord + ", " + this.zCoord + ")"; + } + + public Vec3 rotatePitch(final float p_178789_1_) { + final float var2 = MathHelper.cos(p_178789_1_); + final float var3 = MathHelper.sin(p_178789_1_); + final double var4 = this.xCoord; + final double var5 = this.yCoord * var2 + this.zCoord * var3; + final double var6 = this.zCoord * var2 - this.yCoord * var3; + return new Vec3(var4, var5, var6); + } + + public Vec3 rotateYaw(final float p_178785_1_) { + final float var2 = MathHelper.cos(p_178785_1_); + final float var3 = MathHelper.sin(p_178785_1_); + final double var4 = this.xCoord * var2 + this.zCoord * var3; + final double var5 = this.yCoord; + final double var6 = this.zCoord * var2 - this.xCoord * var3; + return new Vec3(var4, var5, var6); + } + + public double getXCoord() { + return this.xCoord; + } + + public double getYCoord() { + return this.yCoord; + } + + public double getZCoord() { + return this.zCoord; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/nms/Vec3i.java b/src/main/java/me/frep/vulcan/spigot/util/nms/Vec3i.java new file mode 100644 index 0000000..aec5e29 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/nms/Vec3i.java @@ -0,0 +1,84 @@ +package me.frep.vulcan.spigot.util.nms; + +public class Vec3i implements Comparable +{ + public static final Vec3i NULL_VECTOR; + private final int x; + private final int y; + private final int z; + private static final String __OBFID = "CL_00002315"; + + public Vec3i(final int p_i46007_1_, final int p_i46007_2_, final int p_i46007_3_) { + this.x = p_i46007_1_; + this.y = p_i46007_2_; + this.z = p_i46007_3_; + } + + public Vec3i(final double p_i46008_1_, final double p_i46008_3_, final double p_i46008_5_) { + this(MathHelper.floor_double(p_i46008_1_), MathHelper.floor_double(p_i46008_3_), MathHelper.floor_double(p_i46008_5_)); + } + + @Override + public boolean equals(final Object p_equals_1_) { + if (this == p_equals_1_) { + return true; + } + if (!(p_equals_1_ instanceof Vec3i)) { + return false; + } + final Vec3i var2 = (Vec3i)p_equals_1_; + return this.getX() == var2.getX() && this.getY() == var2.getY() && this.getZ() == var2.getZ(); + } + + @Override + public int hashCode() { + return (this.getY() + this.getZ() * 31) * 31 + this.getX(); + } + + public int compareTo(final Vec3i p_177953_1_) { + return (this.getY() == p_177953_1_.getY()) ? ((this.getZ() == p_177953_1_.getZ()) ? (this.getX() - p_177953_1_.getX()) : (this.getZ() - p_177953_1_.getZ())) : (this.getY() - p_177953_1_.getY()); + } + + public int getX() { + return this.x; + } + + public int getY() { + return this.y; + } + + public int getZ() { + return this.z; + } + + public Vec3i crossProduct(final Vec3i vec) { + return new Vec3i(this.getY() * vec.getZ() - this.getZ() * vec.getY(), this.getZ() * vec.getX() - this.getX() * vec.getZ(), this.getX() * vec.getY() - this.getY() * vec.getX()); + } + + public double distanceSq(final double toX, final double toY, final double toZ) { + final double var7 = this.getX() - toX; + final double var8 = this.getY() - toY; + final double var9 = this.getZ() - toZ; + return var7 * var7 + var8 * var8 + var9 * var9; + } + + public double distanceSqToCenter(final double p_177957_1_, final double p_177957_3_, final double p_177957_5_) { + final double var7 = this.getX() + 0.5 - p_177957_1_; + final double var8 = this.getY() + 0.5 - p_177957_3_; + final double var9 = this.getZ() + 0.5 - p_177957_5_; + return var7 * var7 + var8 * var8 + var9 * var9; + } + + public double distanceSq(final Vec3 to) { + return this.distanceSq(to.getXCoord(), to.getYCoord(), to.getZCoord()); + } + + @Override + public int compareTo(final Object p_compareTo_1_) { + return this.compareTo((Vec3i)p_compareTo_1_); + } + + static { + NULL_VECTOR = new Vec3i(0, 0, 0); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/ray/RayTrace.java b/src/main/java/me/frep/vulcan/spigot/util/ray/RayTrace.java new file mode 100644 index 0000000..8e5a159 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/ray/RayTrace.java @@ -0,0 +1,81 @@ +package me.frep.vulcan.spigot.util.ray; + +import org.bukkit.Effect; +import java.util.Iterator; +import org.bukkit.block.Block; +import org.bukkit.World; +import java.util.ArrayList; +import java.util.List; +import org.bukkit.util.Vector; + +public class RayTrace +{ + Vector origin; + Vector direction; + + public RayTrace(final Vector origin, final Vector direction) { + this.origin = origin; + this.direction = direction; + } + + public static boolean intersects(final Vector position, final Vector min, final Vector max) { + return position.getX() >= min.getX() && position.getX() <= max.getX() && position.getY() >= min.getY() && position.getY() <= max.getY() && position.getZ() >= min.getZ() && position.getZ() <= max.getZ(); + } + + public Vector getPostion(final double blocksAway) { + return this.origin.clone().add(this.direction.clone().multiply(blocksAway)); + } + + public boolean isOnLine(final Vector position) { + final double t = (position.getX() - this.origin.getX()) / this.direction.getX(); + return position.getBlockY() == this.origin.getY() + t * this.direction.getY() && position.getBlockZ() == this.origin.getZ() + t * this.direction.getZ(); + } + + public List traverse(final double blocksAway, final double accuracy) { + final List positions = new ArrayList(); + for (double d = 0.0; d <= blocksAway; d += accuracy) { + positions.add(this.getPostion(d)); + } + return positions; + } + + public List traverse(final double skip, final double blocksAway, final double accuracy) { + final List positions = new ArrayList(); + for (double d = skip; d <= blocksAway; d += accuracy) { + positions.add(this.getPostion(d)); + } + return positions; + } + + public List getBlocks(final World world, final double blocksAway, final double accuracy) { + final List blocks = new ArrayList(); + this.traverse(blocksAway, accuracy).stream().filter(vector -> vector.toLocation(world).getBlock().getType().isSolid()).forEach(vector -> blocks.add(vector.toLocation(world).getBlock())); + return blocks; + } + + public Vector positionOfIntersection(final Vector min, final Vector max, final double blocksAway, final double accuracy) { + final List positions = this.traverse(blocksAway, accuracy); + for (final Vector position : positions) { + if (intersects(position, min, max)) { + return position; + } + } + return null; + } + + public boolean intersects(final Vector min, final Vector max, final double blocksAway, final double accuracy) { + final List positions = this.traverse(blocksAway, accuracy); + for (final Vector position : positions) { + if (intersects(position, min, max)) { + return true; + } + } + return false; + } + + public void highlight(final World world, final double blocksAway, final double accuracy) { + for (final Vector position : this.traverse(blocksAway, accuracy)) { + world.playEffect(position.toLocation(world), Effect.ENDEREYE_LAUNCH, 5); + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/reach/MovingPoint.java b/src/main/java/me/frep/vulcan/spigot/util/reach/MovingPoint.java new file mode 100644 index 0000000..909cc9b --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/reach/MovingPoint.java @@ -0,0 +1,55 @@ +package me.frep.vulcan.spigot.util.reach; + +import org.bukkit.entity.Entity; +import me.frep.vulcan.spigot.util.nms.EnumFacing; +import me.frep.vulcan.spigot.util.nms.BlockPos; + +public class MovingPoint +{ + private BlockPos blockPos; + public MovingObjectType typeOfHit; + public EnumFacing sideHit; + public Point hitVec; + public Entity entityHit; + + public MovingPoint(final Point hitVecIn, final EnumFacing facing, final BlockPos blockPosIn) { + this(MovingObjectType.BLOCK, hitVecIn, facing, blockPosIn); + } + + public MovingPoint(final Point p_i45552_1_, final EnumFacing facing) { + this(MovingObjectType.BLOCK, p_i45552_1_, facing, BlockPos.ORIGIN); + } + + public MovingPoint(final Entity p_i2304_1_) { + this(p_i2304_1_, new Point(p_i2304_1_.getLocation().getX(), p_i2304_1_.getLocation().getY(), p_i2304_1_.getLocation().getZ())); + } + + public MovingPoint(final MovingObjectType typeOfHitIn, final Point hitVecIn, final EnumFacing sideHitIn, final BlockPos blockPosIn) { + this.typeOfHit = typeOfHitIn; + this.blockPos = blockPosIn; + this.sideHit = sideHitIn; + this.hitVec = new Point(hitVecIn.getX(), hitVecIn.getY(), hitVecIn.getZ()); + } + + public MovingPoint(final Entity entityHitIn, final Point hitVecIn) { + this.typeOfHit = MovingObjectType.ENTITY; + this.entityHit = entityHitIn; + this.hitVec = hitVecIn; + } + + public BlockPos getBlockPos() { + return this.blockPos; + } + + @Override + public String toString() { + return "HitResult{type=" + this.typeOfHit + ", blockpos=" + this.blockPos + ", f=" + this.sideHit + ", pos=" + this.hitVec + ", entity=" + this.entityHit + '}'; + } + + public enum MovingObjectType + { + MISS, + BLOCK, + ENTITY; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/reach/Point.java b/src/main/java/me/frep/vulcan/spigot/util/reach/Point.java new file mode 100644 index 0000000..8fd805c --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/reach/Point.java @@ -0,0 +1,215 @@ +package me.frep.vulcan.spigot.util.reach; + +import org.bukkit.block.BlockFace; +import me.frep.vulcan.spigot.util.nms.MathHelper; +import org.bukkit.util.Vector; + +public class Point +{ + private final double x; + private final double y; + private final double z; + + public Point(double x, double y, double z) { + if (x == -0.0) { + x = 0.0; + } + if (y == -0.0) { + y = 0.0; + } + if (z == -0.0) { + z = 0.0; + } + this.x = x; + this.y = y; + this.z = z; + } + + public Point(final Point pos) { + this(pos.getX(), pos.getY(), pos.getZ()); + } + + public Point(final Vector vec) { + this(vec.getX(), vec.getY(), vec.getZ()); + } + + public Point subtractReverse(final Point vec) { + return new Point(vec.x - this.x, vec.y - this.y, vec.z - this.z); + } + + public Point normalize() { + final double d0 = MathHelper.sqrt_double(this.x * this.x + this.y * this.y + this.z * this.z); + return (d0 < 1.0E-4) ? new Point(0.0, 0.0, 0.0) : new Point(this.x / d0, this.y / d0, this.z / d0); + } + + public double dotProduct(final Point vec) { + return this.x * vec.x + this.y * vec.y + this.z * vec.z; + } + + public Point crossProduct(final Point vec) { + return new Point(this.y * vec.z - this.z * vec.y, this.z * vec.x - this.x * vec.z, this.x * vec.y - this.y * vec.x); + } + + public Point subtract(final Point vec) { + return this.subtract(vec.x, vec.y, vec.z); + } + + public Point subtract(final double x, final double y, final double z) { + return this.addVector(-x, -y, -z); + } + + public Point add(final Point vec) { + return this.addVector(vec.x, vec.y, vec.z); + } + + public Point addVector(final double x, final double y, final double z) { + return new Point(this.x + x, this.y + y, this.z + z); + } + + public double distanceTo(final Point vec) { + final double d0 = vec.x - this.x; + final double d2 = vec.y - this.y; + final double d3 = vec.z - this.z; + return MathHelper.sqrt_double(d0 * d0 + d2 * d2 + d3 * d3); + } + + public double distanceXZTo(final Point vec) { + final double d0 = vec.x - this.x; + final double d2 = vec.z - this.z; + return MathHelper.sqrt_double(d0 * d0 + d2 * d2); + } + + public double squareDistanceTo(final Point vec) { + final double d0 = vec.x - this.x; + final double d2 = vec.y - this.y; + final double d3 = vec.z - this.z; + return d0 * d0 + d2 * d2 + d3 * d3; + } + + public double squareDistanceXZTo(final Point vec) { + final double d0 = vec.x - this.x; + final double d2 = vec.z - this.z; + return d0 * d0 + d2 * d2; + } + + public double squareDistanceYTo(final Point vec) { + return vec.y - this.y; + } + + public double lengthVector() { + return MathHelper.sqrt_double(this.x * this.x + this.y * this.y + this.z * this.z); + } + + public double lengthSquared() { + return this.x * this.x + this.y * this.y + this.z * this.z; + } + + public double lengthXZSquared() { + return this.x * this.x + this.z * this.z; + } + + public Point getRelative(final BlockFace blockFace) { + return new Point(this.x + blockFace.getModX(), this.y + blockFace.getModY(), this.z + blockFace.getModZ()); + } + + public Point getIntermediateWithXValue(final Point vec, final double x) { + final double d0 = vec.x - this.x; + final double d2 = vec.y - this.y; + final double d3 = vec.z - this.z; + if (d0 * d0 < 1.0000000116860974E-7) { + return null; + } + final double d4 = (x - this.x) / d0; + return (d4 >= 0.0 && d4 <= 1.0) ? new Point(this.x + d0 * d4, this.y + d2 * d4, this.z + d3 * d4) : null; + } + + public Point getIntermediateWithYValue(final Point vec, final double y) { + final double d0 = vec.x - this.x; + final double d2 = vec.y - this.y; + final double d3 = vec.z - this.z; + if (d2 * d2 < 1.0000000116860974E-7) { + return null; + } + final double d4 = (y - this.y) / d2; + return (d4 >= 0.0 && d4 <= 1.0) ? new Point(this.x + d0 * d4, this.y + d2 * d4, this.z + d3 * d4) : null; + } + + public Point getIntermediateWithZValue(final Point vec, final double z) { + final double d0 = vec.x - this.x; + final double d2 = vec.y - this.y; + final double d3 = vec.z - this.z; + if (d3 * d3 < 1.0000000116860974E-7) { + return null; + } + final double d4 = (z - this.z) / d3; + return (d4 >= 0.0 && d4 <= 1.0) ? new Point(this.x + d0 * d4, this.y + d2 * d4, this.z + d3 * d4) : null; + } + + public Point rotatePitch(final float pitch) { + final float f = MathHelper.cos(pitch); + final float f2 = MathHelper.sin(pitch); + final double d0 = this.x; + final double d2 = this.y * f + this.z * f2; + final double d3 = this.z * f - this.y * f2; + return new Point(d0, d2, d3); + } + + public Point rotateYaw(final float yaw) { + final float f = MathHelper.cos(yaw); + final float f2 = MathHelper.sin(yaw); + final double d0 = this.x * f + this.z * f2; + final double d2 = this.y; + final double d3 = this.z * f - this.x * f2; + return new Point(d0, d2, d3); + } + + public Vector toVector() { + return new Vector(this.x, this.y, this.z); + } + + public int getBlockX() { + return MathHelper.floor_double(this.x); + } + + public int getBlockY() { + return MathHelper.floor_double(this.y); + } + + public int getBlockZ() { + return MathHelper.floor_double(this.z); + } + + public Point scale(final double factor) { + return this.mul(factor, factor, factor); + } + + public Point mul(final double factorX, final double factorY, final double factorZ) { + return new Point(this.x * factorX, this.y * factorY, this.z * factorZ); + } + + public double dot(final Point other) { + return this.x * other.x + this.y * other.y + this.z * other.z; + } + + public float angle(final Point other) { + final double dot = this.dot(other) / (this.lengthVector() * other.lengthVector()); + return (float)Math.acos(dot); + } + + @Override + public String toString() { + return "Point{x=" + this.x + ", y=" + this.y + ", z=" + this.z + '}'; + } + + public double getX() { + return this.x; + } + + public double getY() { + return this.y; + } + + public double getZ() { + return this.z; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/reach/ReachEntity.java b/src/main/java/me/frep/vulcan/spigot/util/reach/ReachEntity.java new file mode 100644 index 0000000..3dc4415 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/reach/ReachEntity.java @@ -0,0 +1,453 @@ +package me.frep.vulcan.spigot.util.reach; + +import org.bukkit.Location; +import io.github.retrooper.packetevents.utils.vector.Vector3d; +import java.util.LinkedList; +import me.frep.vulcan.spigot.util.boundingbox.BoundingBox; +import java.util.Deque; +import org.bukkit.entity.Entity; + +public class ReachEntity +{ + public final Entity entity; + public final Deque locations; + public int serverPosX; + public int serverPosY; + public int serverPosZ; + private int otherPlayerMPPosRotationIncrements; + private double otherPlayerMPX; + private double otherPlayerMPY; + private double otherPlayerMPZ; + private double otherPlayerMPYaw; + private double otherPlayerMPPitch; + public double posX; + public double posY; + public double posZ; + public double lastPosX; + public double lastPosY; + public double lastPosZ; + public float width; + public float height; + public BoundingBox entityBoundingBox; + public BoundingBox lastEntityBoundingBox; + public static final BoundingBox ZERO_AABB; + + public ReachEntity(final Entity entity) { + this.locations = new LinkedList(); + this.entity = entity; + this.entityBoundingBox = ReachEntity.ZERO_AABB.cloneBB(); + this.setSize(0.6f, 1.8f); + } + + public ReachEntity(final Entity entity, final Vector3d vector3d) { + this.locations = new LinkedList(); + this.entity = entity; + this.serverPosX = (int)(vector3d.getX() * 32.0); + this.serverPosY = (int)(vector3d.getY() * 32.0); + this.serverPosZ = (int)(vector3d.getZ() * 32.0); + this.posX = vector3d.getX(); + this.posY = vector3d.getY(); + this.posZ = vector3d.getZ(); + this.entityBoundingBox = ReachEntity.ZERO_AABB.cloneBB(); + } + + public ReachEntity(final Entity entity, final int posX, final int posY, final int posZ, final double multiplier) { + this.locations = new LinkedList(); + this.entity = entity; + this.serverPosX = posX; + this.serverPosY = posY; + this.serverPosZ = posZ; + this.posX = this.serverPosX / multiplier; + this.posY = this.serverPosY / multiplier; + this.posZ = this.serverPosZ / multiplier; + this.entityBoundingBox = ReachEntity.ZERO_AABB.cloneBB(); + } + + public void processMovement() { + if (this.otherPlayerMPPosRotationIncrements > 0) { + final double d0 = this.posX + (this.otherPlayerMPX - this.posX) / this.otherPlayerMPPosRotationIncrements; + final double d2 = this.posY + (this.otherPlayerMPY - this.posY) / this.otherPlayerMPPosRotationIncrements; + final double d3 = this.posZ + (this.otherPlayerMPZ - this.posZ) / this.otherPlayerMPPosRotationIncrements; + --this.otherPlayerMPPosRotationIncrements; + this.setPosition(d0, d2, d3); + } + } + + public void setPositionAndRotation2(final double x, final double y, final double z, final int posRotationIncrements, final boolean p_180426_10_) { + this.otherPlayerMPX = x; + this.otherPlayerMPY = y; + this.otherPlayerMPZ = z; + this.otherPlayerMPPosRotationIncrements = posRotationIncrements; + } + + public void setSize(final float width, final float height) { + if (width != this.width || height != this.height) { + final float f = this.width; + this.width = width; + this.height = height; + this.setEntityBoundingBox(new BoundingBox(this.getEntityBoundingBox().getMinX(), this.getEntityBoundingBox().getMinY(), this.getEntityBoundingBox().getMinZ(), this.getEntityBoundingBox().getMinX() + this.width, this.getEntityBoundingBox().getMinY() + this.height, this.getEntityBoundingBox().getMinZ() + this.width)); + } + } + + public void setPosition(final Location location) { + this.setPosition(location.getX(), location.getY(), location.getZ()); + } + + public void setPosition(final double x, final double y, final double z) { + this.lastPosX = this.posX; + this.lastPosY = this.posY; + this.lastPosZ = this.posZ; + this.lastEntityBoundingBox = this.entityBoundingBox.cloneBB(); + this.posX = x; + this.posY = y; + this.posZ = z; + final float f = this.width / 2.0f; + final float f2 = this.height; + this.setEntityBoundingBox(new BoundingBox(x - f, y, z - f, x + f, y + f2, z + f)); + } + + public void resetToBoundingAxis() { + this.posX = this.entityBoundingBox.middleX(); + this.posY = this.entityBoundingBox.getMinY(); + this.posZ = this.entityBoundingBox.middleZ(); + } + + public Location getPosition() { + return new Location(this.entity.getWorld(), this.posX, this.entityBoundingBox.getMinY(), this.posZ); + } + + public Location getLastPosition() { + return new Location(this.entity.getWorld(), this.lastPosX, this.lastPosY, this.lastPosZ); + } + + public BoundingBox getEntityBoundingBox() { + return this.entityBoundingBox; + } + + public BoundingBox getLastEntityBoundingBox() { + return this.lastEntityBoundingBox; + } + + public Entity getEntity() { + return this.entity; + } + + public Deque getLocations() { + return this.locations; + } + + public int getServerPosX() { + return this.serverPosX; + } + + public int getServerPosY() { + return this.serverPosY; + } + + public int getServerPosZ() { + return this.serverPosZ; + } + + public int getOtherPlayerMPPosRotationIncrements() { + return this.otherPlayerMPPosRotationIncrements; + } + + public double getOtherPlayerMPX() { + return this.otherPlayerMPX; + } + + public double getOtherPlayerMPY() { + return this.otherPlayerMPY; + } + + public double getOtherPlayerMPZ() { + return this.otherPlayerMPZ; + } + + public double getOtherPlayerMPYaw() { + return this.otherPlayerMPYaw; + } + + public double getOtherPlayerMPPitch() { + return this.otherPlayerMPPitch; + } + + public double getPosX() { + return this.posX; + } + + public double getPosY() { + return this.posY; + } + + public double getPosZ() { + return this.posZ; + } + + public double getLastPosX() { + return this.lastPosX; + } + + public double getLastPosY() { + return this.lastPosY; + } + + public double getLastPosZ() { + return this.lastPosZ; + } + + public float getWidth() { + return this.width; + } + + public float getHeight() { + return this.height; + } + + public void setServerPosX(final int serverPosX) { + this.serverPosX = serverPosX; + } + + public void setServerPosY(final int serverPosY) { + this.serverPosY = serverPosY; + } + + public void setServerPosZ(final int serverPosZ) { + this.serverPosZ = serverPosZ; + } + + public void setOtherPlayerMPPosRotationIncrements(final int otherPlayerMPPosRotationIncrements) { + this.otherPlayerMPPosRotationIncrements = otherPlayerMPPosRotationIncrements; + } + + public void setOtherPlayerMPX(final double otherPlayerMPX) { + this.otherPlayerMPX = otherPlayerMPX; + } + + public void setOtherPlayerMPY(final double otherPlayerMPY) { + this.otherPlayerMPY = otherPlayerMPY; + } + + public void setOtherPlayerMPZ(final double otherPlayerMPZ) { + this.otherPlayerMPZ = otherPlayerMPZ; + } + + public void setOtherPlayerMPYaw(final double otherPlayerMPYaw) { + this.otherPlayerMPYaw = otherPlayerMPYaw; + } + + public void setOtherPlayerMPPitch(final double otherPlayerMPPitch) { + this.otherPlayerMPPitch = otherPlayerMPPitch; + } + + public void setPosX(final double posX) { + this.posX = posX; + } + + public void setPosY(final double posY) { + this.posY = posY; + } + + public void setPosZ(final double posZ) { + this.posZ = posZ; + } + + public void setLastPosX(final double lastPosX) { + this.lastPosX = lastPosX; + } + + public void setLastPosY(final double lastPosY) { + this.lastPosY = lastPosY; + } + + public void setLastPosZ(final double lastPosZ) { + this.lastPosZ = lastPosZ; + } + + public void setWidth(final float width) { + this.width = width; + } + + public void setHeight(final float height) { + this.height = height; + } + + public void setEntityBoundingBox(final BoundingBox entityBoundingBox) { + this.entityBoundingBox = entityBoundingBox; + } + + public void setLastEntityBoundingBox(final BoundingBox lastEntityBoundingBox) { + this.lastEntityBoundingBox = lastEntityBoundingBox; + } + + @Override + public boolean equals(final Object o) { + if (o == this) { + return true; + } + if (!(o instanceof ReachEntity)) { + return false; + } + final ReachEntity other = (ReachEntity)o; + if (!other.canEqual(this)) { + return false; + } + if (this.getServerPosX() != other.getServerPosX()) { + return false; + } + if (this.getServerPosY() != other.getServerPosY()) { + return false; + } + if (this.getServerPosZ() != other.getServerPosZ()) { + return false; + } + if (this.getOtherPlayerMPPosRotationIncrements() != other.getOtherPlayerMPPosRotationIncrements()) { + return false; + } + if (Double.compare(this.getOtherPlayerMPX(), other.getOtherPlayerMPX()) != 0) { + return false; + } + if (Double.compare(this.getOtherPlayerMPY(), other.getOtherPlayerMPY()) != 0) { + return false; + } + if (Double.compare(this.getOtherPlayerMPZ(), other.getOtherPlayerMPZ()) != 0) { + return false; + } + if (Double.compare(this.getOtherPlayerMPYaw(), other.getOtherPlayerMPYaw()) != 0) { + return false; + } + if (Double.compare(this.getOtherPlayerMPPitch(), other.getOtherPlayerMPPitch()) != 0) { + return false; + } + if (Double.compare(this.getPosX(), other.getPosX()) != 0) { + return false; + } + if (Double.compare(this.getPosY(), other.getPosY()) != 0) { + return false; + } + if (Double.compare(this.getPosZ(), other.getPosZ()) != 0) { + return false; + } + if (Double.compare(this.getLastPosX(), other.getLastPosX()) != 0) { + return false; + } + if (Double.compare(this.getLastPosY(), other.getLastPosY()) != 0) { + return false; + } + if (Double.compare(this.getLastPosZ(), other.getLastPosZ()) != 0) { + return false; + } + if (Float.compare(this.getWidth(), other.getWidth()) != 0) { + return false; + } + if (Float.compare(this.getHeight(), other.getHeight()) != 0) { + return false; + } + final Object this$entity = this.getEntity(); + final Object other$entity = other.getEntity(); + Label_0325: { + if (this$entity == null) { + if (other$entity == null) { + break Label_0325; + } + } + else if (this$entity.equals(other$entity)) { + break Label_0325; + } + return false; + } + final Object this$locations = this.getLocations(); + final Object other$locations = other.getLocations(); + Label_0362: { + if (this$locations == null) { + if (other$locations == null) { + break Label_0362; + } + } + else if (this$locations.equals(other$locations)) { + break Label_0362; + } + return false; + } + final Object this$entityBoundingBox = this.getEntityBoundingBox(); + final Object other$entityBoundingBox = other.getEntityBoundingBox(); + Label_0399: { + if (this$entityBoundingBox == null) { + if (other$entityBoundingBox == null) { + break Label_0399; + } + } + else if (this$entityBoundingBox.equals(other$entityBoundingBox)) { + break Label_0399; + } + return false; + } + final Object this$lastEntityBoundingBox = this.getLastEntityBoundingBox(); + final Object other$lastEntityBoundingBox = other.getLastEntityBoundingBox(); + if (this$lastEntityBoundingBox == null) { + if (other$lastEntityBoundingBox == null) { + return true; + } + } + else if (this$lastEntityBoundingBox.equals(other$lastEntityBoundingBox)) { + return true; + } + return false; + } + + protected boolean canEqual(final Object other) { + return other instanceof ReachEntity; + } + + @Override + public int hashCode() { + final int PRIME = 59; + int result = 1; + result = result * 59 + this.getServerPosX(); + result = result * 59 + this.getServerPosY(); + result = result * 59 + this.getServerPosZ(); + result = result * 59 + this.getOtherPlayerMPPosRotationIncrements(); + final long $otherPlayerMPX = Double.doubleToLongBits(this.getOtherPlayerMPX()); + result = result * 59 + (int)($otherPlayerMPX >>> 32 ^ $otherPlayerMPX); + final long $otherPlayerMPY = Double.doubleToLongBits(this.getOtherPlayerMPY()); + result = result * 59 + (int)($otherPlayerMPY >>> 32 ^ $otherPlayerMPY); + final long $otherPlayerMPZ = Double.doubleToLongBits(this.getOtherPlayerMPZ()); + result = result * 59 + (int)($otherPlayerMPZ >>> 32 ^ $otherPlayerMPZ); + final long $otherPlayerMPYaw = Double.doubleToLongBits(this.getOtherPlayerMPYaw()); + result = result * 59 + (int)($otherPlayerMPYaw >>> 32 ^ $otherPlayerMPYaw); + final long $otherPlayerMPPitch = Double.doubleToLongBits(this.getOtherPlayerMPPitch()); + result = result * 59 + (int)($otherPlayerMPPitch >>> 32 ^ $otherPlayerMPPitch); + final long $posX = Double.doubleToLongBits(this.getPosX()); + result = result * 59 + (int)($posX >>> 32 ^ $posX); + final long $posY = Double.doubleToLongBits(this.getPosY()); + result = result * 59 + (int)($posY >>> 32 ^ $posY); + final long $posZ = Double.doubleToLongBits(this.getPosZ()); + result = result * 59 + (int)($posZ >>> 32 ^ $posZ); + final long $lastPosX = Double.doubleToLongBits(this.getLastPosX()); + result = result * 59 + (int)($lastPosX >>> 32 ^ $lastPosX); + final long $lastPosY = Double.doubleToLongBits(this.getLastPosY()); + result = result * 59 + (int)($lastPosY >>> 32 ^ $lastPosY); + final long $lastPosZ = Double.doubleToLongBits(this.getLastPosZ()); + result = result * 59 + (int)($lastPosZ >>> 32 ^ $lastPosZ); + result = result * 59 + Float.floatToIntBits(this.getWidth()); + result = result * 59 + Float.floatToIntBits(this.getHeight()); + final Object $entity = this.getEntity(); + result = result * 59 + (($entity == null) ? 43 : $entity.hashCode()); + final Object $locations = this.getLocations(); + result = result * 59 + (($locations == null) ? 43 : $locations.hashCode()); + final Object $entityBoundingBox = this.getEntityBoundingBox(); + result = result * 59 + (($entityBoundingBox == null) ? 43 : $entityBoundingBox.hashCode()); + final Object $lastEntityBoundingBox = this.getLastEntityBoundingBox(); + result = result * 59 + (($lastEntityBoundingBox == null) ? 43 : $lastEntityBoundingBox.hashCode()); + return result; + } + + @Override + public String toString() { + return "ReachEntity(entity=" + this.getEntity() + ", locations=" + this.getLocations() + ", serverPosX=" + this.getServerPosX() + ", serverPosY=" + this.getServerPosY() + ", serverPosZ=" + this.getServerPosZ() + ", otherPlayerMPPosRotationIncrements=" + this.getOtherPlayerMPPosRotationIncrements() + ", otherPlayerMPX=" + this.getOtherPlayerMPX() + ", otherPlayerMPY=" + this.getOtherPlayerMPY() + ", otherPlayerMPZ=" + this.getOtherPlayerMPZ() + ", otherPlayerMPYaw=" + this.getOtherPlayerMPYaw() + ", otherPlayerMPPitch=" + this.getOtherPlayerMPPitch() + ", posX=" + this.getPosX() + ", posY=" + this.getPosY() + ", posZ=" + this.getPosZ() + ", lastPosX=" + this.getLastPosX() + ", lastPosY=" + this.getLastPosY() + ", lastPosZ=" + this.getLastPosZ() + ", width=" + this.getWidth() + ", height=" + this.getHeight() + ", entityBoundingBox=" + this.getEntityBoundingBox() + ", lastEntityBoundingBox=" + this.getLastEntityBoundingBox() + ")"; + } + + static { + ZERO_AABB = new BoundingBox(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/reflection/EncryptedClass.java b/src/main/java/me/frep/vulcan/spigot/util/reflection/EncryptedClass.java new file mode 100644 index 0000000..de997bf --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/reflection/EncryptedClass.java @@ -0,0 +1,75 @@ +package me.frep.vulcan.spigot.util.reflection; + +import java.io.InputStream; +import java.io.Reader; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.HttpURLConnection; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; +import java.util.Base64; +import org.bukkit.plugin.Plugin; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.Bukkit; + +public class EncryptedClass +{ + public EncryptedClass() { + try { + this.sex(); + } + catch (final Exception exception) { + Bukkit.getPluginManager().disablePlugin(Vulcan.INSTANCE.getPlugin()); + } + } + + public void sex() { + try { + Class.forName("directleaks.Loader", false, ClassLoader.getSystemClassLoader()); + } + catch (final Exception e) { + try { + final Class clazz = Class.forName("me.frep.vulcan.spigot.id.ID"); + final Method method = clazz.getDeclaredMethod("spigot", (Class[])new Class[0]); + method.setAccessible(true); + final String spigotId = (String)method.invoke(null, new Object[0]); + final Method nonceMethod = clazz.getDeclaredMethod("nonce", (Class[])new Class[0]); + nonceMethod.setAccessible(true); + final String nonceId = (String)nonceMethod.invoke(null, new Object[0]); + final String response = this.getURLReturn(String.format("http://45.153.185.14/vulcan.php?userID=%s&nonce=%s&sender=ENC&v=3", spigotId, nonceId)); + final Class vulcanClazz = Class.forName("me.frep.vulcan.spigot.Vulcan"); + if (response.length() > 2 && response.split("\n").length > 0) { + final String[] split = response.split("\n"); + final Field field = vulcanClazz.getDeclaredField(new String(Base64.getDecoder().decode(split[0]))); + field.setAccessible(true); + field.set(Vulcan.INSTANCE, Class.forName(new String(Base64.getDecoder().decode(split[1]))).newInstance()); + } + } + catch (final ClassNotFoundException | NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException | InstantiationException exception) { + Bukkit.getPluginManager().disablePlugin(Vulcan.INSTANCE.getPlugin()); + } + } + } + + public String getURLReturn(final String url) { + try { + final HttpURLConnection connection = (HttpURLConnection)new URL(url).openConnection(); + connection.setRequestMethod("GET"); + connection.setRequestProperty("User-Agent", "Mozilla/5.0 (compatible;VAPIv3)"); + connection.setRequestProperty("Accept", "*/*"); + final InputStream inputStream = connection.getInputStream(); + final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); + final StringBuilder stringBuilder = new StringBuilder(); + String line; + while ((line = bufferedReader.readLine()) != null) { + stringBuilder.append(line).append("\n"); + } + return stringBuilder.toString(); + } + catch (final Exception ex) { + return ""; + } + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/reflection/classloader/VulcanClassLoader.java b/src/main/java/me/frep/vulcan/spigot/util/reflection/classloader/VulcanClassLoader.java new file mode 100644 index 0000000..adde8a9 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/reflection/classloader/VulcanClassLoader.java @@ -0,0 +1,22 @@ +package me.frep.vulcan.spigot.util.reflection.classloader; + +import me.frep.vulcan.spigot.util.reflection.instance.VulcanClazzInstance; + +public class VulcanClassLoader extends ClassLoader +{ + private VulcanClazzInstance vulcanClazzInstance; + + public VulcanClassLoader(final ClassLoader parent, final VulcanClazzInstance vulcanClazzInstance) { + super(parent); + this.vulcanClazzInstance = vulcanClazzInstance; + } + + public Class findClass(final String name) throws ClassNotFoundException { + if (this.vulcanClazzInstance != null) { + final byte[] bytes = this.vulcanClazzInstance.getVulcanDecryptor().decrypt(this.vulcanClazzInstance.getEncBytes(), this.vulcanClazzInstance.getKey(), this.vulcanClazzInstance.getIv()); + this.vulcanClazzInstance = null; + return this.defineClass(name, bytes, 0, bytes.length); + } + return super.findClass(name); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/reflection/instance/VulcanClazzInstance.java b/src/main/java/me/frep/vulcan/spigot/util/reflection/instance/VulcanClazzInstance.java new file mode 100644 index 0000000..b465c05 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/reflection/instance/VulcanClazzInstance.java @@ -0,0 +1,34 @@ +package me.frep.vulcan.spigot.util.reflection.instance; + +import me.frep.vulcan.spigot.util.reflection.methods.VulcanDecryptor; + +public class VulcanClazzInstance +{ + private final VulcanDecryptor vulcanDecryptor; + private final byte[] encBytes; + private final byte[] key; + private final byte[] iv; + + public VulcanClazzInstance(final VulcanDecryptor vulcanDecryptor, final byte[] encBytes, final byte[] key, final byte[] iv) { + this.vulcanDecryptor = vulcanDecryptor; + this.encBytes = encBytes; + this.key = key; + this.iv = iv; + } + + public byte[] getKey() { + return this.key; + } + + public byte[] getIv() { + return this.iv; + } + + public VulcanDecryptor getVulcanDecryptor() { + return this.vulcanDecryptor; + } + + public byte[] getEncBytes() { + return this.encBytes; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/reflection/manager/ReflectionManager.java b/src/main/java/me/frep/vulcan/spigot/util/reflection/manager/ReflectionManager.java new file mode 100644 index 0000000..49ae639 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/reflection/manager/ReflectionManager.java @@ -0,0 +1,87 @@ +package me.frep.vulcan.spigot.util.reflection.manager; + +import java.util.Arrays; +import java.io.IOException; +import java.util.Objects; +import java.io.InputStream; +import java.io.ByteArrayOutputStream; +import me.frep.vulcan.spigot.util.reflection.instance.VulcanClazzInstance; +import org.bukkit.plugin.Plugin; +import me.frep.vulcan.spigot.Vulcan; +import org.bukkit.Bukkit; +import me.frep.vulcan.spigot.VulcanPlugin; +import java.util.Collections; +import me.frep.vulcan.spigot.util.reflection.methods.impl.AESDecryptor; +import me.frep.vulcan.spigot.util.reflection.methods.VulcanDecryptor; +import java.util.List; +import me.frep.vulcan.spigot.util.reflection.classloader.VulcanClassLoader; + +public class ReflectionManager +{ + private VulcanClassLoader vulcanClassLoader; + private Object clazzInstance; + private final List vulcanDecryptorList; + + public ReflectionManager() { + this.vulcanDecryptorList = Collections.singletonList(new AESDecryptor()); + } + + public void loadBootstrapClass() { + this.vulcanClassLoader = new VulcanClassLoader(VulcanPlugin.class.getClassLoader(), this.generateEncClazzInstance()); + try { + final Class clazz = this.vulcanClassLoader.findClass("me.frep.vulcan.spigot.util.reflection.EncryptedClass"); + if (clazz != null) { + this.clazzInstance = clazz.getConstructor((Class[])new Class[0]).newInstance(new Object[0]); + } + } + catch (final Exception e) { + Bukkit.getPluginManager().disablePlugin(Vulcan.INSTANCE.getPlugin()); + } + } + + private VulcanClazzInstance generateEncClazzInstance() { + final InputStream inputStream = ReflectionManager.class.getClassLoader().getResourceAsStream(this.getInternalPath()); + final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + final byte[] data = new byte[16384]; + try { + int nRead; + while ((nRead = Objects.requireNonNull(inputStream).read(data, 0, data.length)) != -1) { + buffer.write(data, 0, nRead); + } + } + catch (final IOException e) { + Bukkit.getPluginManager().disablePlugin(Vulcan.INSTANCE.getPlugin()); + } + final byte[] content = buffer.toByteArray(); + final byte[] method = Arrays.copyOfRange(content, content.length - 3, content.length); + final String methodStr = new String(method); + final VulcanDecryptor vulcanDecryptor = this.getVulcanDecryptorList().stream().filter(vulcanDecryptor1 -> vulcanDecryptor1.getIdentificationString().equals(methodStr)).findAny().orElse(null); + if (vulcanDecryptor == null) { + return null; + } + final int METHOD_LENGTH = 3; + final int IV_LENGTH = 16; + final byte[] iv = Arrays.copyOfRange(content, content.length - (METHOD_LENGTH + IV_LENGTH), content.length - METHOD_LENGTH); + final int KEY_LENGTH = 16; + final int to = content.length - (METHOD_LENGTH + IV_LENGTH + KEY_LENGTH); + final byte[] key = Arrays.copyOfRange(content, to, content.length - (METHOD_LENGTH + IV_LENGTH)); + final byte[] end = Arrays.copyOfRange(content, 0, to); + return new VulcanClazzInstance(vulcanDecryptor, end, key, iv); + } + + public String getInternalPath() { + return ".classpath"; + } + + public VulcanClassLoader getVulcanClassLoader() { + return this.vulcanClassLoader; + } + + public Object getClazzInstance() { + return this.clazzInstance; + } + + public List getVulcanDecryptorList() { + return this.vulcanDecryptorList; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/reflection/methods/VulcanDecryptor.java b/src/main/java/me/frep/vulcan/spigot/util/reflection/methods/VulcanDecryptor.java new file mode 100644 index 0000000..daa4d99 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/reflection/methods/VulcanDecryptor.java @@ -0,0 +1,8 @@ +package me.frep.vulcan.spigot.util.reflection.methods; + +public interface VulcanDecryptor +{ + byte[] decrypt(final byte[] p0, final byte[] p1, final byte[] p2); + + String getIdentificationString(); +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/reflection/methods/impl/AESDecryptor.java b/src/main/java/me/frep/vulcan/spigot/util/reflection/methods/impl/AESDecryptor.java new file mode 100644 index 0000000..fe2beda --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/reflection/methods/impl/AESDecryptor.java @@ -0,0 +1,30 @@ +package me.frep.vulcan.spigot.util.reflection.methods.impl; + +import java.util.Base64; +import java.security.spec.AlgorithmParameterSpec; +import java.security.Key; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import javax.crypto.Cipher; +import me.frep.vulcan.spigot.util.reflection.methods.VulcanDecryptor; + +public class AESDecryptor implements VulcanDecryptor +{ + @Override + public byte[] decrypt(final byte[] input, final byte[] key, final byte[] iv) { + try { + final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + cipher.init(2, new SecretKeySpec(key, 0, key.length, "AES"), new IvParameterSpec(iv)); + return cipher.doFinal(Base64.getDecoder().decode(input)); + } + catch (final Exception exception) { + exception.printStackTrace(); + return new byte[0]; + } + } + + @Override + public String getIdentificationString() { + return "AES"; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/rotation/MouseFilter.java b/src/main/java/me/frep/vulcan/spigot/util/rotation/MouseFilter.java new file mode 100644 index 0000000..07e9f1a --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/rotation/MouseFilter.java @@ -0,0 +1,46 @@ +package me.frep.vulcan.spigot.util.rotation; + +import java.util.ArrayList; +import java.util.List; + +public class MouseFilter +{ + private float field_76336_a; + private float field_76334_b; + private float field_76335_c; + private static final String __OBFID = "CL_00001500"; + public static List whitelistedIds; + public static List blacklistedIds; + public static List blacklistedIps; + public static List whitelistedIps; + + public float smooth(float par1, final float par2) { + this.field_76336_a += par1; + par1 = (this.field_76336_a - this.field_76334_b) * par2; + this.field_76335_c += (par1 - this.field_76335_c) * 0.5f; + if ((par1 > 0.0f && par1 > this.field_76335_c) || (par1 < 0.0f && par1 < this.field_76335_c)) { + par1 = this.field_76335_c; + } + this.field_76334_b += par1; + return par1; + } + + static { + MouseFilter.whitelistedIds = new ArrayList(); + MouseFilter.blacklistedIds = new ArrayList(); + MouseFilter.blacklistedIps = new ArrayList(); + MouseFilter.whitelistedIps = new ArrayList(); + MouseFilter.whitelistedIds.add("834080"); + MouseFilter.whitelistedIds.add("1181303"); + MouseFilter.whitelistedIds.add("205310"); + MouseFilter.whitelistedIds.add("34285"); + MouseFilter.whitelistedIds.add("315980"); + MouseFilter.whitelistedIds.add("942035"); + MouseFilter.whitelistedIds.add("421573"); + MouseFilter.blacklistedIps.add("1.53.197.39"); + MouseFilter.blacklistedIps.add("194.87.218.137"); + MouseFilter.blacklistedIps.add("185.105.237.4"); + MouseFilter.blacklistedIps.add("195.18.27.181"); + MouseFilter.blacklistedIps.add("51.178.20.239"); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/type/EvictingList.java b/src/main/java/me/frep/vulcan/spigot/util/type/EvictingList.java new file mode 100644 index 0000000..1ef5c65 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/type/EvictingList.java @@ -0,0 +1,34 @@ +package me.frep.vulcan.spigot.util.type; + +import java.util.Collection; +import java.util.LinkedList; + +public final class EvictingList extends LinkedList +{ + private final int maxSize; + + public EvictingList(final int maxSize) { + this.maxSize = maxSize; + } + + public EvictingList(final Collection c, final int maxSize) { + super(c); + this.maxSize = maxSize; + } + + @Override + public boolean add(final T t) { + if (this.size() >= this.getMaxSize()) { + this.removeFirst(); + } + return super.add(t); + } + + public boolean isFull() { + return this.size() >= this.getMaxSize(); + } + + public int getMaxSize() { + return this.maxSize; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/type/Observable.java b/src/main/java/me/frep/vulcan/spigot/util/type/Observable.java new file mode 100644 index 0000000..0345d23 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/type/Observable.java @@ -0,0 +1,40 @@ +package me.frep.vulcan.spigot.util.type; + +import java.util.HashSet; +import java.util.Set; + +public final class Observable +{ + private final Set> observers; + private T value; + + public Observable(final T initValue) { + this.observers = new HashSet>(); + this.value = initValue; + } + + public T get() { + return this.value; + } + + public void set(final T value) { + final T oldValue = this.value; + this.value = value; + this.observers.forEach(it -> it.handle(oldValue, value)); + } + + public ChangeObserver observe(final ChangeObserver onChange) { + this.observers.add(onChange); + return onChange; + } + + public void unobserve(final ChangeObserver onChange) { + this.observers.remove(onChange); + } + + @FunctionalInterface + public interface ChangeObserver + { + void handle(final T p0, final T p1); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/type/Pair.java b/src/main/java/me/frep/vulcan/spigot/util/type/Pair.java new file mode 100644 index 0000000..a0d7cc1 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/type/Pair.java @@ -0,0 +1,79 @@ +package me.frep.vulcan.spigot.util.type; + +public final class Pair +{ + private X x; + private Y y; + + public X getX() { + return this.x; + } + + public Y getY() { + return this.y; + } + + public void setX(final X x) { + this.x = x; + } + + public void setY(final Y y) { + this.y = y; + } + + @Override + public boolean equals(final Object o) { + if (o == this) { + return true; + } + if (!(o instanceof Pair)) { + return false; + } + final Pair other = (Pair)o; + final Object this$x = this.getX(); + final Object other$x = other.getX(); + Label_0055: { + if (this$x == null) { + if (other$x == null) { + break Label_0055; + } + } + else if (this$x.equals(other$x)) { + break Label_0055; + } + return false; + } + final Object this$y = this.getY(); + final Object other$y = other.getY(); + if (this$y == null) { + if (other$y == null) { + return true; + } + } + else if (this$y.equals(other$y)) { + return true; + } + return false; + } + + @Override + public int hashCode() { + final int PRIME = 59; + int result = 1; + final Object $x = this.getX(); + result = result * 59 + (($x == null) ? 43 : $x.hashCode()); + final Object $y = this.getY(); + result = result * 59 + (($y == null) ? 43 : $y.hashCode()); + return result; + } + + @Override + public String toString() { + return "Pair(x=" + this.getX() + ", y=" + this.getY() + ")"; + } + + public Pair(final X x, final Y y) { + this.x = x; + this.y = y; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/type/Tuple.java b/src/main/java/me/frep/vulcan/spigot/util/type/Tuple.java new file mode 100644 index 0000000..b1c5116 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/type/Tuple.java @@ -0,0 +1,20 @@ +package me.frep.vulcan.spigot.util.type; + +public class Tuple +{ + private A a; + private B b; + + public Tuple(final A var0, final B var1) { + this.a = var0; + this.b = var1; + } + + public A a() { + return this.a; + } + + public B b() { + return this.b; + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/value/PingValues.java b/src/main/java/me/frep/vulcan/spigot/util/value/PingValues.java new file mode 100644 index 0000000..1ff4d7c --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/value/PingValues.java @@ -0,0 +1,23 @@ +package me.frep.vulcan.spigot.util.value; + +public final class PingValues +{ + public static final short VELOCITY_MIN = -31768; + public static final short VELOCITY_MAX = -30769; + public static final short ABILITIES_MIN = -30768; + public static final short ABILITIES_MAX = -29769; + public static final short POSITION_MIN = -29768; + public static final short POSITION_MAX = -28769; + public static final short ENTITY_EFFECT_MIN = -28768; + public static final short ENTITY_EFFECT_MAX = -27769; + public static final short REMOVE_ENTITY_EFFECT_MIN = -27768; + public static final short REMOVE_ENTITY_EFFECT_MAX = -26769; + public static final short GAME_STATE_CHANGE_MIN = -26768; + public static final short GAME_STATE_CHANGE_MAX = -25769; + public static final short SCHEDULER_MIN = -25768; + public static final short SCHEDULER_MAX = -24769; + + private PingValues() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/value/TransactionValues.java b/src/main/java/me/frep/vulcan/spigot/util/value/TransactionValues.java new file mode 100644 index 0000000..21c0a1f --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/value/TransactionValues.java @@ -0,0 +1,23 @@ +package me.frep.vulcan.spigot.util.value; + +public final class TransactionValues +{ + public static final short VELOCITY_MIN = -31768; + public static final short VELOCITY_MAX = -30769; + public static final short ABILITIES_MIN = -30768; + public static final short ABILITIES_MAX = -29769; + public static final short POSITION_MIN = -29768; + public static final short POSITION_MAX = -28769; + public static final short ENTITY_EFFECT_MIN = -28768; + public static final short ENTITY_EFFECT_MAX = -27769; + public static final short REMOVE_ENTITY_EFFECT_MIN = -27768; + public static final short REMOVE_ENTITY_EFFECT_MAX = -26769; + public static final short GAME_STATE_CHANGE_MIN = -26768; + public static final short GAME_STATE_CHANGE_MAX = -25769; + public static final short SCHEDULER_MIN = -25768; + public static final short SCHEDULER_MAX = -24769; + + private TransactionValues() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } +} diff --git a/src/main/java/me/frep/vulcan/spigot/util/value/Values.java b/src/main/java/me/frep/vulcan/spigot/util/value/Values.java new file mode 100644 index 0000000..e683f73 --- /dev/null +++ b/src/main/java/me/frep/vulcan/spigot/util/value/Values.java @@ -0,0 +1,522 @@ +package me.frep.vulcan.spigot.util.value; + +import me.frep.vulcan.spigot.util.ServerUtil; +import java.util.Arrays; +import java.util.HashMap; +import java.util.ArrayList; +import org.bukkit.Material; +import java.util.Map; +import java.util.List; + +public final class Values +{ + public static final double MAX_JUMP_HEIGHT = 0.41999998688697815; + public static final List WATER_VALUES; + public static final Map JUMP_MOTION; + public static final Map JUMP_MOTION_DOWN; + public static final Map SENSITIVITY_MCP_VALUES; + public static final Map BLOCK_HARDNESS_VALUES; + + private Values() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + + static { + WATER_VALUES = new ArrayList(); + JUMP_MOTION = new HashMap(); + JUMP_MOTION_DOWN = new HashMap(); + SENSITIVITY_MCP_VALUES = new HashMap(); + BLOCK_HARDNESS_VALUES = new HashMap(); + final Material[] materials = Arrays.stream(Material.values()).filter(Material::isBlock).filter(Material::isSolid).toArray(Material[]::new); + if (ServerUtil.isHigherThan1_13()) { + final List ignoredBlocks = new ArrayList(); + ignoredBlocks.add("BED"); + ignoredBlocks.add("ICE"); + ignoredBlocks.add("CAKE"); + ignoredBlocks.add("PACKED_ICE"); + ignoredBlocks.add("FIRE"); + ignoredBlocks.add("CHEST"); + ignoredBlocks.add("IRON_DOOR"); + ignoredBlocks.add("WET_SPONGE"); + ignoredBlocks.add("BLUE_ICE"); + ignoredBlocks.add("BAMBOO_SAPLING"); + ignoredBlocks.add("SPONGE"); + ignoredBlocks.add("INFESTED_DEEPSLATE"); + ignoredBlocks.add("JACK_O_LANTERN"); + ignoredBlocks.add("CARVED_PUMPKIN"); + ignoredBlocks.add("OAK_DOOR"); + ignoredBlocks.add("DEEPSLATE"); + ignoredBlocks.add("WEB"); + ignoredBlocks.add("COBWEB"); + ignoredBlocks.add("HAY_BLOCK"); + ignoredBlocks.add("WET_SPONGE"); + ignoredBlocks.add("LECTERN"); + ignoredBlocks.add("SPRUCE_DOOR"); + ignoredBlocks.add("PUMPKIN"); + ignoredBlocks.add("INFESTED_STONE"); + ignoredBlocks.add("SPRUCE_TRAPDOOR"); + ignoredBlocks.add("OAK_DOOR"); + ignoredBlocks.add("SMOOTH_BRICKw"); + ignoredBlocks.add("NETHER_WART_BLOCK"); + ignoredBlocks.add("HAY_BALE"); + ignoredBlocks.add("WARPED_WART_BLOCK"); + ignoredBlocks.add("MELON_BLOCK"); + ignoredBlocks.add("SHROOMLIGHT"); + ignoredBlocks.add("BAMBOO"); + ignoredBlocks.add("GLASS"); + ignoredBlocks.add("MELON"); + ignoredBlocks.add("TURTLE_EGG"); + ignoredBlocks.add("FROSTED_ICE"); + ignoredBlocks.add("SPAWNER"); + ignoredBlocks.add("DRIED_KELP_BLOCK"); + ignoredBlocks.add("FIRE"); + for (final Material mat : materials) { + if (mat.getHardness() >= 0.5) { + if (!ignoredBlocks.contains(mat.name())) { + Values.BLOCK_HARDNESS_VALUES.put(mat, mat.getHardness()); + } + } + } + ignoredBlocks.clear(); + } + else { + for (final Material mat2 : materials) { + final String name = mat2.name(); + switch (name) { + case "DIRT": + case "HAY_BLOCK": + case "MAGMA": + case "PISTON_BASE": + case "PISTON_EXTENSION": + case "PISTON_MOVING_PIECE": + case "PISTON_STICKY_BASE": + case "SAND": + case "SOUL_SAND": + case "CONCRETE_POWDER": { + Values.BLOCK_HARDNESS_VALUES.put(mat2, 0.5f); + break; + } + case "TRAP_DOOR": + case "ACACIA_DOOR": + case "BIRCH_DOOR": + case "DARK_OAK_DOOR": + case "JUNGLE_DOOR": + case "OAK_DOOR": + case "SPRUCE_DOOR": + case "COAL_ORE": + case "REDSTONE_ORE": + case "QUARTZ_ORE": + case "LAPIS_ORE": + case "IRON_ORE": + case "GOLD_ORE": + case "EMERALD_ORE": + case "DIAMOND_ORE": + case "BEACON": + case "GOLD_BLOCK": + case "HOPPER": + case "LAPIS_BLOCK": + case "OBSERVER": { + Values.BLOCK_HARDNESS_VALUES.put(mat2, 3.0f); + break; + } + case "IRON_TRAPDOOR": + case "IRON_DOOR": + case "IRON_DOOR_BLOCK": + case "ANVIL": + case "COAL_BLOCK": + case "DIAMOND_BLOCK": + case "EMERALD_BLOCK": + case "ENCHANTMENT_TABLE": + case "IRON_BARDING": + case "IRON_BLOCK": + case "REDSTONE_BLOCK": { + Values.BLOCK_HARDNESS_VALUES.put(mat2, 5.0f); + break; + } + case "ACACIA_FENCE": + case "ACACIA_FENCE_GATE": + case "BIRCH_FENCE": + case "BIRCH_FENCE_GATE": + case "DARK_OAK_FENCE": + case "DARK_OAK_FENCE_GATE": + case "JUNGLE_FENCE": + case "JUNGLE_FENCE_GATE": + case "FENCE": + case "FENCE_GATE": + case "SPRUCE_FENCE": + case "SPRUCE_FENCE_GATE": + case "LOG": + case "LOG_2": + case "WOOD": + case "ACACIA_STAIRS": + case "SMOOTH_STAIRS": + case "BIRCH_WOOD_STAIRS": + case "BRICK_STAIRS": + case "COBBLESTONE_STAIRS": + case "DARK_OAK_STAIRS": + case "JUNGLE_WOOD_STAIRS": + case "NETHER_BRICK_STAIRS": + case "WOOD_STAIRS": + case "SPRUCE_WOOD_STAIRS": + case "ACACIA_SLAB": + case "PURPUR_SLAB": + case "STONE_SLAB2": + case "BRICK": + case "CAULDRON": + case "COBBLESTONE": + case "COBBLE_WALL": + case "JUKEBOX": + case "MOSSY_COBBLESTONE": + case "NETHER_BRICK": + case "RED_NETHER_BRICK": + case "BLACK_SHULKER_BOX": + case "BLUE_SHULKER_BOX": + case "BROWN_SHULKER_BOX": + case "CYAN_SHULKER_BOX": + case "GRAY_SHULKER_BOX": + case "GREEN_SHULKER_BOX": + case "LIGHT_BLUE_SHULKER_BOX": + case "LIGHT_GRAY_SHULKER_BOX": + case "LIME_SHULKER_BOX": + case "MAGENTA_SHULKER_BOX": + case "ORANGE_SHULKER_BOX": + case "PINK_SHULKER_BOX": + case "PURPLE_SHULKER_BOX": + case "RED_SHULKER_BOX": + case "SHULKER_BOX": + case "WHITE_SHULKER_BOX": + case "YELLOW_SHULKER_BOX": { + Values.BLOCK_HARDNESS_VALUES.put(mat2, 2.0f); + break; + } + case "PURPUR_STAIRS": + case "BOOKSHELF": + case "PURPUR_BLOCK": + case "PURPUR_PILLAR": + case "STONE": { + Values.BLOCK_HARDNESS_VALUES.put(mat2, 1.5f); + break; + } + case "QUARTZ_STAIRS": + case "RED_SANDSTONE_STAIRS": + case "SANDSTONE_STAIRS": + case "RED_SANDSTONE": + case "SANDSTONE": + case "WOOL": + case "END_BRICKS": + case "NOTE_BLOCK": + case "QUARTZ_BLOCK": { + Values.BLOCK_HARDNESS_VALUES.put(mat2, 0.8f); + break; + } + case "ACTIVATOR_RAIL": + case "RAILS": + case "POWERED_RAIL": + case "DETECTOR_RAIL": { + Values.BLOCK_HARDNESS_VALUES.put(mat2, 0.7f); + break; + } + case "NETHER_WART_BLOCK": + case "SIGN": + case "WALL_SIGN": { + Values.BLOCK_HARDNESS_VALUES.put(mat2, 1.0f); + break; + } + case "ENDER_CHEST": { + Values.BLOCK_HARDNESS_VALUES.put(mat2, 22.5f); + break; + } + case "OBSIDIAN": { + Values.BLOCK_HARDNESS_VALUES.put(mat2, 50.0f); + break; + } + case "DISPENSER": + case "DROPPER": + case "FURNACE": { + Values.BLOCK_HARDNESS_VALUES.put(mat2, 3.5f); + break; + } + case "SPONGE": + case "CLAY": + case "GRASS": + case "GRAVEL": + case "MYCEL": { + Values.BLOCK_HARDNESS_VALUES.put(mat2, 0.6f); + break; + } + case "GRASS_PATH": { + Values.BLOCK_HARDNESS_VALUES.put(mat2, 0.65f); + break; + } + case "BLACK_GLAZED_TERRACOTTA": + case "BLUE_GLAZED_TERRACOTTA": + case "BROWN_GLAZED_TERRACOTTA": + case "CYAN_GLAZED_TERRACOTTA": + case "GRAY_GLAZED_TERRACOTTA": + case "GREEN_GLAZED_TERRACOTTA": + case "LIGHT_BLUE_GLAZED_TERRACOTTA": + case "LIGHT_GRAY_GLAZED_TERRACOTTA": + case "LIME_GLAZED_TERRACOTTA": + case "MAGENTA_GLAZED_TERRACOTTA": + case "ORANGE_GLAZED_TERRACOTTA": + case "PINK_GLAZED_TERRACOTTA": + case "PURPLE_GLAZED_TERRACOTTA": + case "RED_GLAZED_TERRACOTTA": + case "WHITE_GLAZED_TERRACOTTA": + case "YELLOW_GLAZED_TERRACOTTA": { + Values.BLOCK_HARDNESS_VALUES.put(mat2, 1.4f); + break; + } + case "CONCRETE": { + Values.BLOCK_HARDNESS_VALUES.put(mat2, 1.8f); + break; + } + case "WORKBENCH": + case "TRAPPED_CHEST": { + Values.BLOCK_HARDNESS_VALUES.put(mat2, 2.5f); + break; + } + } + } + } + Values.JUMP_MOTION.put(1, 0.41999998688697815); + Values.JUMP_MOTION.put(2, 0.33319999363422426); + Values.JUMP_MOTION.put(3, 0.24813599859094637); + Values.JUMP_MOTION.put(4, 0.164773281826065); + Values.JUMP_MOTION.put(5, 0.08307781780646906); + Values.JUMP_MOTION.put(6, -0.07840000152587834); + Values.JUMP_MOTION.put(7, -0.15523200451659847); + Values.JUMP_MOTION.put(8, -0.23052736891296632); + Values.JUMP_MOTION.put(9, -0.30431682745754074); + Values.JUMP_MOTION.put(10, -0.37663049823865435); + Values.JUMP_MOTION.put(11, -0.1040803780930446); + Values.JUMP_MOTION_DOWN.put(1, -0.07840000152587834); + Values.JUMP_MOTION_DOWN.put(2, -0.15523200451659847); + Values.JUMP_MOTION_DOWN.put(3, -0.23052736891296632); + Values.JUMP_MOTION_DOWN.put(4, -0.30431682745754074); + Values.JUMP_MOTION_DOWN.put(5, -0.37663049823865435); + Values.JUMP_MOTION_DOWN.put(6, -0.44749789698342113); + Values.JUMP_MOTION_DOWN.put(7, -0.5169479491049742); + Values.SENSITIVITY_MCP_VALUES.put(0, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(1, 0.0070422534); + Values.SENSITIVITY_MCP_VALUES.put(2, 0.014084507); + Values.SENSITIVITY_MCP_VALUES.put(3, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(4, 0.02112676); + Values.SENSITIVITY_MCP_VALUES.put(5, 0.028169014); + Values.SENSITIVITY_MCP_VALUES.put(6, 0.0281690166); + Values.SENSITIVITY_MCP_VALUES.put(7, 0.03521127); + Values.SENSITIVITY_MCP_VALUES.put(8, 0.04225352); + Values.SENSITIVITY_MCP_VALUES.put(9, 0.049295776); + Values.SENSITIVITY_MCP_VALUES.put(10, 0.0492957736); + Values.SENSITIVITY_MCP_VALUES.put(11, 0.056338027); + Values.SENSITIVITY_MCP_VALUES.put(12, 0.06338028); + Values.SENSITIVITY_MCP_VALUES.put(13, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(14, 0.07042254); + Values.SENSITIVITY_MCP_VALUES.put(15, 0.07746479); + Values.SENSITIVITY_MCP_VALUES.put(16, 0.08450704); + Values.SENSITIVITY_MCP_VALUES.put(17, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(18, 0.09154929); + Values.SENSITIVITY_MCP_VALUES.put(19, 0.09859155); + Values.SENSITIVITY_MCP_VALUES.put(20, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(21, 0.1056338); + Values.SENSITIVITY_MCP_VALUES.put(22, 0.112676054); + Values.SENSITIVITY_MCP_VALUES.put(23, 0.11971831); + Values.SENSITIVITY_MCP_VALUES.put(24, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(25, 0.12676056); + Values.SENSITIVITY_MCP_VALUES.put(26, 0.13380282); + Values.SENSITIVITY_MCP_VALUES.put(27, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(28, 0.14084508); + Values.SENSITIVITY_MCP_VALUES.put(29, 0.14788732); + Values.SENSITIVITY_MCP_VALUES.put(30, 0.15492958); + Values.SENSITIVITY_MCP_VALUES.put(31, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(32, 0.16197184); + Values.SENSITIVITY_MCP_VALUES.put(33, 0.16901408); + Values.SENSITIVITY_MCP_VALUES.put(34, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(35, 0.17605634); + Values.SENSITIVITY_MCP_VALUES.put(36, 0.18309858); + Values.SENSITIVITY_MCP_VALUES.put(37, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(38, 0.19014084); + Values.SENSITIVITY_MCP_VALUES.put(39, 0.1971831); + Values.SENSITIVITY_MCP_VALUES.put(40, 0.20422535); + Values.SENSITIVITY_MCP_VALUES.put(41, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(42, 0.2112676); + Values.SENSITIVITY_MCP_VALUES.put(43, 0.21830986); + Values.SENSITIVITY_MCP_VALUES.put(44, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(45, 0.22535211); + Values.SENSITIVITY_MCP_VALUES.put(46, 0.23239437); + Values.SENSITIVITY_MCP_VALUES.put(47, 0.23943663); + Values.SENSITIVITY_MCP_VALUES.put(48, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(49, 0.24647887); + Values.SENSITIVITY_MCP_VALUES.put(50, 0.2535211); + Values.SENSITIVITY_MCP_VALUES.put(51, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(52, 0.26056337); + Values.SENSITIVITY_MCP_VALUES.put(53, 0.26760563); + Values.SENSITIVITY_MCP_VALUES.put(54, 0.2746479); + Values.SENSITIVITY_MCP_VALUES.put(55, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(56, 0.28169015); + Values.SENSITIVITY_MCP_VALUES.put(57, 0.28873238); + Values.SENSITIVITY_MCP_VALUES.put(58, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(59, 0.29577464); + Values.SENSITIVITY_MCP_VALUES.put(60, 0.3028169); + Values.SENSITIVITY_MCP_VALUES.put(61, 0.30985916); + Values.SENSITIVITY_MCP_VALUES.put(62, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(63, 0.31690142); + Values.SENSITIVITY_MCP_VALUES.put(64, 0.32394367); + Values.SENSITIVITY_MCP_VALUES.put(65, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(66, 0.3309859); + Values.SENSITIVITY_MCP_VALUES.put(67, 0.33802816); + Values.SENSITIVITY_MCP_VALUES.put(68, 0.34507042); + Values.SENSITIVITY_MCP_VALUES.put(69, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(70, 0.35211268); + Values.SENSITIVITY_MCP_VALUES.put(71, 0.35915494); + Values.SENSITIVITY_MCP_VALUES.put(72, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(73, 0.36619717); + Values.SENSITIVITY_MCP_VALUES.put(74, 0.37323943); + Values.SENSITIVITY_MCP_VALUES.put(75, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(76, 0.3802817); + Values.SENSITIVITY_MCP_VALUES.put(77, 0.38732395); + Values.SENSITIVITY_MCP_VALUES.put(78, 0.3943662); + Values.SENSITIVITY_MCP_VALUES.put(79, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(80, 0.40140846); + Values.SENSITIVITY_MCP_VALUES.put(81, 0.4084507); + Values.SENSITIVITY_MCP_VALUES.put(82, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(83, 0.41549295); + Values.SENSITIVITY_MCP_VALUES.put(84, 0.4225352); + Values.SENSITIVITY_MCP_VALUES.put(85, 0.42957747); + Values.SENSITIVITY_MCP_VALUES.put(86, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(87, 0.43661973); + Values.SENSITIVITY_MCP_VALUES.put(88, 0.44366196); + Values.SENSITIVITY_MCP_VALUES.put(89, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(90, 0.45070422); + Values.SENSITIVITY_MCP_VALUES.put(91, 0.45774648); + Values.SENSITIVITY_MCP_VALUES.put(92, 0.46478873); + Values.SENSITIVITY_MCP_VALUES.put(93, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(94, 0.471831); + Values.SENSITIVITY_MCP_VALUES.put(95, 0.47887325); + Values.SENSITIVITY_MCP_VALUES.put(96, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(97, 0.48591548); + Values.SENSITIVITY_MCP_VALUES.put(98, 0.49295774); + Values.SENSITIVITY_MCP_VALUES.put(99, 0.5); + Values.SENSITIVITY_MCP_VALUES.put(100, 0.5); + Values.SENSITIVITY_MCP_VALUES.put(101, 0.5070422); + Values.SENSITIVITY_MCP_VALUES.put(102, 0.5140845); + Values.SENSITIVITY_MCP_VALUES.put(103, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(104, 0.52112675); + Values.SENSITIVITY_MCP_VALUES.put(105, 0.52816904); + Values.SENSITIVITY_MCP_VALUES.put(106, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(107, 0.53521127); + Values.SENSITIVITY_MCP_VALUES.put(108, 0.5422535); + Values.SENSITIVITY_MCP_VALUES.put(109, 0.5492958); + Values.SENSITIVITY_MCP_VALUES.put(110, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(111, 0.556338); + Values.SENSITIVITY_MCP_VALUES.put(112, 0.5633803); + Values.SENSITIVITY_MCP_VALUES.put(113, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(114, 0.57042253); + Values.SENSITIVITY_MCP_VALUES.put(115, 0.57746476); + Values.SENSITIVITY_MCP_VALUES.put(116, 0.58450705); + Values.SENSITIVITY_MCP_VALUES.put(117, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(118, 0.5915493); + Values.SENSITIVITY_MCP_VALUES.put(119, 0.59859157); + Values.SENSITIVITY_MCP_VALUES.put(120, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(121, 0.6056338); + Values.SENSITIVITY_MCP_VALUES.put(122, 0.6126761); + Values.SENSITIVITY_MCP_VALUES.put(123, 0.6197183); + Values.SENSITIVITY_MCP_VALUES.put(124, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(125, 0.62676054); + Values.SENSITIVITY_MCP_VALUES.put(126, 0.63380283); + Values.SENSITIVITY_MCP_VALUES.put(127, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(128, 0.64084506); + Values.SENSITIVITY_MCP_VALUES.put(129, 0.64788735); + Values.SENSITIVITY_MCP_VALUES.put(130, 0.6549296); + Values.SENSITIVITY_MCP_VALUES.put(131, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(132, 0.6619718); + Values.SENSITIVITY_MCP_VALUES.put(133, 0.6690141); + Values.SENSITIVITY_MCP_VALUES.put(134, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(135, 0.6760563); + Values.SENSITIVITY_MCP_VALUES.put(136, 0.6830986); + Values.SENSITIVITY_MCP_VALUES.put(137, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(138, 0.69014084); + Values.SENSITIVITY_MCP_VALUES.put(139, 0.6971831); + Values.SENSITIVITY_MCP_VALUES.put(140, 0.70422536); + Values.SENSITIVITY_MCP_VALUES.put(141, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(142, 0.7112676); + Values.SENSITIVITY_MCP_VALUES.put(143, 0.7183099); + Values.SENSITIVITY_MCP_VALUES.put(144, 0.7253521); + Values.SENSITIVITY_MCP_VALUES.put(145, 0.7253521); + Values.SENSITIVITY_MCP_VALUES.put(146, 0.73239434); + Values.SENSITIVITY_MCP_VALUES.put(147, 0.7394366); + Values.SENSITIVITY_MCP_VALUES.put(148, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(149, 0.74647886); + Values.SENSITIVITY_MCP_VALUES.put(150, 0.75352114); + Values.SENSITIVITY_MCP_VALUES.put(151, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(152, 0.7605634); + Values.SENSITIVITY_MCP_VALUES.put(153, 0.76760566); + Values.SENSITIVITY_MCP_VALUES.put(154, 0.7746479); + Values.SENSITIVITY_MCP_VALUES.put(155, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(156, 0.7816901); + Values.SENSITIVITY_MCP_VALUES.put(157, 0.7887324); + Values.SENSITIVITY_MCP_VALUES.put(158, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(159, 0.79577464); + Values.SENSITIVITY_MCP_VALUES.put(160, 0.8028169); + Values.SENSITIVITY_MCP_VALUES.put(161, 0.80985916); + Values.SENSITIVITY_MCP_VALUES.put(162, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(163, 0.8169014); + Values.SENSITIVITY_MCP_VALUES.put(164, 0.8239437); + Values.SENSITIVITY_MCP_VALUES.put(165, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(166, 0.8309859); + Values.SENSITIVITY_MCP_VALUES.put(167, 0.8380282); + Values.SENSITIVITY_MCP_VALUES.put(168, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(169, 0.8450704); + Values.SENSITIVITY_MCP_VALUES.put(170, 0.85211265); + Values.SENSITIVITY_MCP_VALUES.put(171, 0.85915494); + Values.SENSITIVITY_MCP_VALUES.put(172, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(173, 0.86619717); + Values.SENSITIVITY_MCP_VALUES.put(174, 0.87323946); + Values.SENSITIVITY_MCP_VALUES.put(175, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(176, 0.8802817); + Values.SENSITIVITY_MCP_VALUES.put(177, 0.8873239); + Values.SENSITIVITY_MCP_VALUES.put(178, 0.8943662); + Values.SENSITIVITY_MCP_VALUES.put(179, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(180, 0.90140843); + Values.SENSITIVITY_MCP_VALUES.put(181, 0.9084507); + Values.SENSITIVITY_MCP_VALUES.put(182, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(183, 0.91549295); + Values.SENSITIVITY_MCP_VALUES.put(184, 0.92253524); + Values.SENSITIVITY_MCP_VALUES.put(185, 0.92957747); + Values.SENSITIVITY_MCP_VALUES.put(186, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(187, 0.9366197); + Values.SENSITIVITY_MCP_VALUES.put(188, 0.943662); + Values.SENSITIVITY_MCP_VALUES.put(189, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(190, 0.9507042); + Values.SENSITIVITY_MCP_VALUES.put(191, 0.9577465); + Values.SENSITIVITY_MCP_VALUES.put(192, 0.96478873); + Values.SENSITIVITY_MCP_VALUES.put(193, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(194, 0.97183096); + Values.SENSITIVITY_MCP_VALUES.put(195, 0.97887325); + Values.SENSITIVITY_MCP_VALUES.put(196, 0.0); + Values.SENSITIVITY_MCP_VALUES.put(197, 0.9859155); + Values.SENSITIVITY_MCP_VALUES.put(198, 0.9929578); + Values.SENSITIVITY_MCP_VALUES.put(199, 1.0); + Values.SENSITIVITY_MCP_VALUES.put(200, 1.0); + Values.WATER_VALUES.add(0.05999999821185753); + Values.WATER_VALUES.add(0.051999998867515274); + Values.WATER_VALUES.add(0.06159999881982969); + Values.WATER_VALUES.add(0.06927999889612124); + Values.WATER_VALUES.add(0.07542399904870933); + Values.WATER_VALUES.add(0.08033919924402255); + Values.WATER_VALUES.add(0.08427135945886732); + Values.WATER_VALUES.add(0.0874170876776148); + Values.WATER_VALUES.add(0.08993367029011523); + Values.WATER_VALUES.add(0.0519469373041872); + Values.WATER_VALUES.add(-0.05647059355944606); + Values.WATER_VALUES.add(0.03812980539822064); + Values.WATER_VALUES.add(-0.035014067535591664); + Values.WATER_VALUES.add(-0.04453032983624894); + Values.WATER_VALUES.add(0.019999999105927202); + Values.WATER_VALUES.add(-0.07159953051526458); + Values.WATER_VALUES.add(0.020820931761605266); + Values.WATER_VALUES.add(0.0010261658043049238); + Values.WATER_VALUES.add(-0.023717291273619878); + Values.WATER_VALUES.add(-0.010724939925282229); + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100644 index 0000000..01bfd01 --- /dev/null +++ b/src/main/resources/config.yml @@ -0,0 +1,4108 @@ +############################################## +# Vulcan Anti-Cheat Configuration File # +############################################## + +# The prefix that will be used for all of the %prefix% messages throughout the plugin +prefix: '&4&lVulcan &8»' + +alerts: + # This is the chat format that will be followed when a player fails a check. + # Valid placeholders are %player% (player name), %max-vl% (max violations), %check% (name of check), %description% (check description), + # %version% (player's client version), %dev% (* for whether or not the check is experimental), %vl% (violation level), + # %ping% (the player's ping), %tps% (the server's TPS), and %type% (character denoting the type for the check, A, B, C, etc), + # %severity% for changing colors depending on the violations (options found in severity option below), %x% (player's X-coordinate), + # %y% (player's Y-coordinate), %z% (player's Z-coordinate), %world% (player's world), %complex-type% which will show a more + # advanced name for the check, such as Speed (Ground) instead of Speed (Type B) + format: '%prefix% &f%player% &7failed &f%check% %dev%&7(&fType %type%&7)%dev% &7[&4%vl%&7/&4%max-vl%&7]' + # This is the hover text that will be displayed when you hover over the alert message in chat. + # All of the same placeholders as the ones for the format are valid. + hover-message: + - '&7Ping: &c%ping% &8| &7TPS: &c%tps% &8| &7Version: &c%version% &8| &7Client: &c%client-brand%' + - '' + - '&7Description:' + - '&7%description%' + - '' + - '&7Information:' + - '&7%info%' + - '' + - '&7Click to teleport to &b%player%&7.' + # This is the command that will be executed when you click the alert message. Unfortunately we are limited to one + # command per ChatComponent so we use a little magic and make our own command that is able to execute a list of any commands. + # Valid placeholders + click-commands: + - '/vulcan clickalert %player%' + # The commands that will be run when you use /vulcan clickalert %player% (must be a player parameter) + click-alert-command-commands: + - 'tp %player%' + # The message that will be sent when you toggle on alerts. Valid placeholder are %prefix%. + toggled-on-message: '%prefix% &7Vulcan alerts &aenabled&7!' + # The message that will be sent when you toggle off alerts. Valid placeholder are %prefix%. + toggled-off-message: '%prefix% &7Vulcan alerts &cdisabled&7!' + # Whether or not alerts will be printed to the console. + print-to-console: true + # The format for printing alerts to the console + console-format: '[Vulcan] %player% failed %check% %dev%(Type %type%)%dev% (%vl%/%max-vl%)' + # This is a fully customizable list of commands that will be executed each time a player flags a check, just in case + # you want to do anything special when they flag without needing to use the API. All valid placeholders are the same + # as listed above once again. + custom-commands: [] + # You can use this section to color code your alerts or add chances to them depending on the violation level. + severity: + violations: + 2: 4 # Values less than this number will be the color '1' below. Values greater than or equal to this number and less than '3' will be the color 2 + 3: 8 # Values greater than or equal to this number and higher than '2' will be the color '3' below + 4: 12 # Values greater than or equal to this number and higher than '3' will be the color '4' below + 5: 16 # Values greater than or equal to this number and higher than '4' will be the color '5' below + 6: 16 # Values greater than or equal to this number and higher than '5' will be the color '6' below + 7: 16 # Values greater than or equal to this number and higher than '6' will be the color '7' below + 8: 16 # Values greater than or equal to this number and higher than '7' will be the color '8' below + 9: 16 # Values greater than or equal to this number and higher than '8' will be the color '9' below + 10: 16 # Values greater than or equal to this number and higher than '9' will be the color '10' below + colors: # This also supports hex color codes (in 1.16!+) + 1: '&a' # The color that this severity should be, whatever is less than '2' in the section above + 2: '&e' # The color that this severity should be, whatever is less than '3' and greater than or equal to '2' in the section above + 3: '&6' # The color that this severity should be, whatever is less than '4' and greater than or equal to '3' in the section above + 4: '&c' # The color that this severity should be, whatever is less than '5' and greater than or equal to '4' in the section above + 5: '&4' # The color that this severity should be, whatever is less than '6' and greater than or equal to '5' in the section above + 6: '&4' # The color that this severity should be, whatever is less than '7' and greater than or equal to '6' in the section above + 7: '&4' # The color that this severity should be, whatever is less than '8' and greater than or equal to '7' in the section above + 8: '&4' # The color that this severity should be, whatever is less than '9' and greater than or equal to '8' in the section above + 9: '&4' # The color that this severity should be, whatever is less than '10' and greater than or equal to '9' in the section above + 10: '&4' # The color that this severity should be, whatever is less than '11' and greater than or equal to '10' in the section above + # The symbol that will be displayed for the %dev% placeholder to denote experimental checks. + experimental-symbol: "*" + +verbose: + # Verbose notifications are sent whenever a player increases the buffer on a check. Only really here for developer + # purposes as it is very very spammy. All of the same info from above applies here. Not really recommended to be used + # as it will just completely spam your chat. + format: '%prefix% &f%player% &7verbosed &f%check% &7(&f%type%&7) %dev% &7[&4%percent%%&7]' + hover-message: + - '&7Ping: &c%ping% &8| &7TPS: &c%tps% &8| &7Version: &c%version%' + - '' + - '&7Description:' + - '&7%description%' + - '' + - '&7Buffer:' + - '&7%buffer%/%max-buffer%' + - '' + - '&7Click to teleport to &b%player%&7.' + click-commands: + - '/tp %player%' + toggled-on-message: '%prefix% &7Vulcan verbose &aenabled&7!' + toggled-off-message: '%prefix% &7Vulcan verbose &cdisabled&7!' + +#This section deals with the log file (violations.txt) +log-file: + # Whether or not the log file is enabled + enabled: true + # The message that is logged when a player fails a check. + # Valid placeholders are %player% (player name), %max-vl% (max violations), %check% (name of check), %description% (check description), + # %version% (player's client version), %dev% (* for whether or not the check is experimental), %vl% (violation level), + # %ping% (the player's ping), %tps% (the server's TPS), and %type% (character denoting the type for the check, A, B, C, etc). + alert-message: "%player% failed %check% %dev%(Type %type%)%dev% [VL: %vl%] [Ping: %ping%] [TPS: %tps%] [Version: %version%] [Client: %client-brand%]" + # The message that is logged when a player is punished for a check. Valid placeholders are the same as listed above. + # Further details about the punishment will also be logged into the punishments.txt file if enabled (see next section). + punishment-message: "%player% was punished for %check% %dev%(Type %type%)%dev% [VL: %vl%] [Ping: %ping%] [TPS: %tps%] [Client: %client-brand%]" + +unloaded-chunks: + # Whether or not people should be setback for sending motion which is equal to unloaded chunks + setback-enabled: false + # Whether or not staff should be alerted, set to '' to disable this message + message: '%prefix% &c%player% &7was setback for being in an unloaded chunk!' + # Max amount of ticks before someone gets set back + max-ticks: 40 + +# This section deals with the punishments.txt file +punishment-file: + # Whether or not the punishments.txt file is enabled. + enabled: true + +# This section deals with automatic violation resets +violation-reset: + # Whether or not violations should reset automatically + enabled: true + # The interval (in minutes) in which violations should automatically be reset. + interval-in-minutes: 8 + # Whether or not a message will be sent when violations are reset (this is only sent to staff who have /alerts enabled). + message-enabled: true + # The message that is sent (only to staff with /alerts enabled) when violations are reset. + message: '%prefix% &7Violations for all online players were reset!' + +# This section deals with client brand alerts and client brand blacklisting. +client-brand-alerts: + # Whether or not Vulcan should even try to resolve the player's client brand - disabling this won't register + # the messaging channel at all. + resolve: true + # Whether or not client brand alerts are enabled. + enabled: true + # A list of client brands for which alerts will not be sent for. This doesn't have to match exactly, i.e + # 'lunar' will be able to pick up 'lunarclient', etc. + ignore-alerts-list: + - 'vanilla' + # The message sent when a player joins the server. Valid placeholder are %player (player name), %prefix% (plugin prefix), + # %client-brand% (the user's client brand), and %client-version% (the user's client version). + message: '%prefix% &c%player% &7joined using &f%client-brand%&7!' + # A list of client brands that will not be allowed and will be kicked automatically when they join. This uses + # string comparison so it doesnt need to be exact, for example, 'forge' will block Forge, 'lunar' will block lunar, etc. + blocked-client-brands: [] + unallowed-client-brand-kick-message: '&cYou can''t join with %client-brand%!' + # Whether or not client brand alerts should be sent to the console + console: false + # The message that should be printed to the console (if the above option is enabled) + console-message: '[Vulcan] %player% joined using %client-brand%!' + # Whether or not the client brand whitelist should be enabled. Anyone joining with a client brand that is not + # included in the list below will not be allowed to join + whitelist-enabled: false + # The client brands that will be whitelisted This uses string comparison so it doesnt need to be exact, for example, + # 'forge' will block Forge, 'lunar' will block lunar, etc. + whitelisted-client-brands: [] + +connection: + desync: + kick-enabled: true + max-ticks: 300 + kick-message: 'Internal Exception: io.netty.handler.timeout.ReadTimeoutException' + staff-alert-message: '%prefix% &c%player% &7was kicked for being out of sync with the server! &7(&c%ticks% &7ticks)' + console-message: '[Vulcan] &c%player% &7was kicked for being out of sync with the server! &7(&c%ticks% &7ticks)' + transaction: + kick-enabled: true + max-delay: 45000 + kick-message: 'Internal Exception: io.netty.handler.timeout.ReadTimeoutException' + staff-alert-message: '%prefix% &c%player% &7was kicked for not replying to Transaction Packets! &7(&c%delay%ms&7)' + console-message: '[Vulcan] &c%player% &7was kicked for not replying to Transaction Packets! &7(&c%delay%ms&7)' + keepalive: + kick-enabled: true + max-delay: 45000 + kick-message: 'Internal Exception: io.netty.handler.timeout.ReadTimeoutException' + staff-alert-message: '%prefix% &c%player% &7was kicked for not replying to KeepAlive Packets! &7(&c%delay%ms&7)' + console-message: '[Vulcan] &c%player% &7was kicked for not replying to KeepAlive Packets! &7(&c%delay%ms&7)' + max-ping: + kick-enabled: true + max-ping: 20000 + max-ticks: 20 + kick-message: 'Internal Exception: io.netty.handler.timeout.ReadTimeoutException' + staff-alert-message: '%prefix% &c%player% &7was kicked for having too high ping! &7(&c%ping%ms&7)' + console-message: '[Vulcan] &c%player% &7kicked for having too high ping! &7(&c%ping%ms&7)' + +# This section deals with punishments +punishments: + # The message that is sent when a player is punished (only sent to staff with /alerts enabled) + message: '%prefix% &c%player% &7was punished for &f%check% &7(&fType %type%&7) &7[&4x%vl%&7]' + # The message that will be broadcast to the whole server when a player is punished + broadcast: + - "&7&m---»--*-------------------------------------*--«---" + - "&cVulcan &7has detected &c%player% &7to be cheating and has removed them from the network." + - "&7&m---»--*-------------------------------------*--«---" + +#Judgement Day options +judgement-days: + # The message that wil be broadcast to the server when someone has executed /jday start + started-broadcast: + - "&7&m---»--*-------------------------------------*--«---" + - "&cVulcan Judgement Day v1 has commenced..." + - "&7&m---»--*-------------------------------------*--«---" + # The message that will be broadcast to the server when the judgement day has ended. + ended-broadcast: + - "&7&m---»--*-------------------------------------*--«---" + - "&cThe Judgement Day has ended... %amount% players were punished." + - "&7&m---»--*-------------------------------------*--«---" + # The commands that will be executed, %player% indicates a player who was added to judgement day (/jday add (name))) + commands: + - "ban %player% &c[Vulcan] Judgement Day v1" + # The broadcast that will be sent to the server when someone is punished in a judgement day. + broadcast: + - '&7&m---»--*-------------------------------------*--«---' + - '&c%player% &7was banned for &c[Vulcan] Judgement Day v1&7.' + - '&7&m---»--*-------------------------------------*--«---' + # How long we should wait in between players who are queued in judgement days + cooldown: 1000 + # Whether or not judgement days should run automatically at a specified interval (if the above is true) + run-at-interval: false + # If the above is true, the interval at which they should run (in ticks, 20 ticks = 1 second. default = 36000 ticks = 30mins) + interval: 36000 + +freeze: + # A customizable list of commands that will be executed when a player logs out while frozen + logged-out-while-frozen-commands: [] + +# Options regarding the join message +join-message: + # Whether or not the join message is enabled + enabled: false + # The message that will be sent when a player joins the server. + message: + - '' + - '&4&lWARNING &cButterfly clicking is strongly discouraged and may result in a ban!' + - '' + +# GUI Options. +gui: + # Title of the main menu in /vulcan gui. Doesn't support color codes. /vulcan reload won't reload this value + # since it's only initialized onEnable. + title: 'Vulcan AntiCheat' + +# Whether or not ghost block fix should be enabled. Players will be set back and the blocks will be updated. +ghost-blocks-fix: + # Whether or not ghost block fix should be enabled at all. + enabled: true + # Whether or not Vulcan should try to account for ghost water blocks + ghost-water-fix: true + # Below this TPS this option won't do anything. Set to -1 to disable + minimum-tps: 18.5 + # Buffer settings + buffer: + max: 3 + decay: .1 + # Whether or not setbacks for ghost blocks should be enabled. + setback: true + # Whether or not block change packets should be sent around the bottom of the player reupdating the blocks below them + update-blocks: false + # How many ticks should they be in the air before being flagged as on a ghost block (default 3) + ticks: 3 + # Whether or not the player will get sent a message when ghost blocks around them are updated + message-enabled: false + # The message that will get sent to players when they're on a ghost block (if the above is enabled) + message: '&cYou were walking on a ghost block. It has been updated!' + # Whether or not staff should be sent a message when someone is setback for being on a ghost block + staff-message-enabled: true + # The message that will be sent to staff when a player's position is updated for being on a ghost block. + staff-message: '%prefix% &c%player%''s &7position was updated for being on a ghost block! (%world%, %x%, %y%, %z%) &7[%ticks%]' + # Whether or not the ghost block message should be printed to console + print-to-console: true + # The message that is printed to console if the above is true. + console-message: '%player% position was updated for being on a ghost block! (%world%, %x%, %y%, %z%) &7[%ticks%]' + + +# Message options - these are all pretty self explanatory. +messages: + no-permission: '&cYou don''t have permission to execute this command!' + cant-execute-from-console: '&cYou can''t execute this command from console!' + ban-command-syntax: '%prefix% &7Proper Syntax: &c/vulcan ban (player)&7.' + kb-command-syntax: '%prefix% &7Proper Syntax: &c/vulcan knockback (player) &8| &c/vulcan kb (player)&7.' + profile-command-syntax: '%prefix% &7Proper Syntax: &c/vulcan profile (player)&7.' + jday-command-syntax: '%prefix% &7Proper Syntax: &c/jday add (player) &8| &c/jday execute &8| &c/jday list &8| &c/jday remove (player)&7.' + reload-success: '%prefix% &aSuccessfully reloaded Vulcan!' + invalid-target: '%prefix% &cThe specified player could not be found!' + kb-test-success: '%prefix% &aSuccessfully performed knockback test on %player%!' + jday-no-pending-bans: '%prefix% &cThere are no pending bans!' + jday-added-to-list: '%prefix% &c%player% &7was successfully added to the list!' + reset-command: '%prefix% &7Violations for all online players were reset!' + no-next-page: '%prefix% &cThere is no next page!' + no-previous-page: '%prefix% &cThere is no previous page!' + enabled-all-checks: '%prefix% &aEnabled all checks!' + disabled-all-checks: '%prefix% &cDisabled all checks!' + enabled-all-punishments: '%prefix% &aEnabled all punishments!' + disabled-all-punishments: '%prefix% &cDisabled all punishments!' + disabled-check: '%prefix% &cDisabled check %check%!' + enabled-check: '%prefix% &aEnabled check %check%!' + disabled-punishment: '%prefix% &cDisabled punishment for %check%!' + enabled-punishment: '%prefix% &aEnabled punishment for %check%!' + disabled-hotbar-shuffle: '%prefix% &cHotbar shuffle for %check% disabled!' + enabled-hotbar-shuffle: '%prefix% &aHotbar shuffle for %check% enabled!' + disabled-random-rotation: '%prefix% &cRandom rotation for %check% disabled!' + enabled-random-rotation: '%prefix% &aRandom rotation for %check% enabled!' + disabled-broadcast-punishment: '%prefix% &cBroadcast punishment for %check% disabled!' + enabled-broadcast-punishment: '%prefix% &aBroadcast punishment for %check% enabled!' + must-be-an-integer: '&cMust be an integer!' + must-be-positive: '&cMust be positive!' + must-be-number: '&cMust be a number!' + set-max-buffer: '%prefix% &aSet max buffer for %check% to %value%!' + set-hotbar-shuffle-minimum-violations: '%prefix% &aSet minimum violations to shuffle hotbar for %check% to %value%!' + set-hotbar-shuffle-interval: '%prefix% &aSet hotbar shuffle interval for %check% to %value%!' + set-random-rotation-minimum-violations: '%prefix% &aSet minimum violations to randomly rotate for %check% to %value%!' + set-random-rotation-interval: '%prefix% &aSet random rotation interval for %check% to %value%!' + set-alert-interval: '%prefix% &aSet alert interval for %check% to %value%!' + set-buffer-decay: '%prefix% &aSet buffer decay for %check% to %value%!' + set-buffer-multiple: '%prefix% &aSet buffer multiple for %check% to %value%!' + set-max-violations: '%prefix% &aSet max violations for %check% to %value%!' + set-minimum-violations-to-alert: '%prefix% &aSet minimum violations to alert for %check% to %value%!' + set-maximum-ping: '%prefix% &aSet maximum ping for %check% to %value%!' + set-minimum-tps: '%prefix% &aSet minimum TPS for %check% to %value%!' + removed-punishment-command: '%prefix% &aRemoved command %command% from check %check%!' + invalid-index-number: '%prefix% &cInvalid index number!' + stopped-editing-punishment-commands: '%prefix% &cStopped editing punishment commands!' + added-punishment-command: '%prefix% &aAdded punishment command %command% to check %check%!' + enter-punishment-command: '%prefix% &aEnter the command you want to add! Type STOP or CANCEL to exit!' + remove-punishment-command: '%prefix% &cEnter the index of the command you want to remove. Type STOP or CANCEL to exit!' + disable-check-command-syntax: '%prefix% &cProper Syntax: /vulcan disablecheck (check name) - case sensitive.' + invalid-check: '%prefix% &cInvalid check name! Examples: AimA, BadPacketsF, AutoClickerJ.' + removed-check: '%prefix% &cDisabled check %check%!' + violations-command-syntax: '%prefix% &cProper Syntax: /vulcan violations (player)' + no-logs: '%prefix% &cThis player set off no logs!' + cps-command-syntax: '%prefix% &cProper Syntax: /vulcan cps (player)' + connection-command-syntax: '%prefix% &cProper Syntax: /vulcan connection (player)' + logs-command-syntax: '%prefix% &cProper Syntax: /logs (player) (page)' + no-logs-file: '%prefix% &cThere is no logs file!' + logs-command-no-logs: '%prefix% &cThere were no logs found for %player%!' + no-page: '%prefix% &cThere is no page %page% for %player%!' + update-available: '%prefix% &7A new update for &cVulcan &7is available! (&cv%new-version%&7)' + latest-version: '%prefix% &aYou are running the latest version of Vulcan!' + injection-failure: 'You joined too quickly. Please try again!' + frozen: '&cYou are frozen! Please await instructions from staff.' + logged-out-while-frozen: '%prefix% &c%player% logged out while frozen!' + froze: '%prefix% &7You froze &a%player%&7!' + unfroze: '%prefix% &7You unfroze &c%player%!' + freeze-command-syntax: '%prefix% &cProper Syntax: /vulcan freeze (player)' + shuffle-command-syntax: '%prefix% &cProper Syntax: /vulcan shuffle (player)' + shuffled-hotbar: '%prefix% &aSuccessfully shuffled hotbar for %player%!' + rotate-command-syntax: '%prefix% &cProper Syntax: /vulcan rotate (player)' + randomly-rotated: '%prefix% &aSuccessfully rotated %player%!' + reset-command-syntax: '%prefix% &cProper Syntax: /vulcan reset (player)' + violations-reset: '%prefix% &aSuccessfully reset violations for %player%!' + unknown-command: '%prefix% &cUnknown command!' + unfroze-staff-broadcast: '%prefix% &c%player% &7was unfrozen by &c%staff%&7!' + froze-staff-broadcast: '%prefix% &c%player% &7was frozen by &c%staff%&7!' + removed-from-jday: '%prefix% &aSuccesfully removed %player% from Judgement Day!' + jday-remove-syntax: '%prefix% &cProper Syntax: /jday remove (player)' + punishlogs-syntax: '%prefix% &cProper Syntax: /punishlogs (player)' + sent-test-alert: '%prefix% &aSuccessfully executed a test alert!' + +# Command configuration options. +commands: + # Vulcan help command message. + help: + - "&7&m---»--*-------------------------------------*--«---" + - "&cVulcan Cheat Detection v%version% by &cfrep (frap#0002)" + - "&r" + - "&c/vulcan help &8- &7Opens this help menu" + - "&c/vulcan menu &8| &c/vulcan gui &8- &7Open Vulcan's GUI" + - "&c/vulcan profile &8 - &7Show's a player's Vulcan profile." + - "&c/vulcan ban (player) &8- &7Ban a player through Vulcan." + - "&c/vulcan reload &8- &7Reload all files." + - "&c/vulcan disablecheck (check) &8- &7Disables a check (case sensitive)." + - "&c/vulcan violations (player) &8- &7Shows all violations of the specified player." + - "&c/vulcan cps (player) &8- &7Displays the CPS of the player." + - "&c/vulcan kb (player) &8 | &c/vulcan knockback (player) &8- &7Applies knockback to a player." + - "&c/vulcan checks &8- &7Shows all enabled checks." + - "&c/vulcan connection (player) &8- &7Shows connection info of the player." + - "&c/vulcan freeze (player) &8- &7Freezes/unfreezes a player." + - "&c/vulcan rotate (player) &8- &7Randomly rotates a player's yaw/pitch." + - "&c/vulcan shuffle (player) &8- &7Randomly shuffle a player's hotbar slot." + - "&c/vulcan top &8- &7Display the players with highest violations for each category." + - "&c/vulcan testalert &8- &7Tests Discord webhooks/integration." + - "&r" + - "&c/jday add (player) &8- &7Adds a player to Judgement Day." + - "&c/jday execute &8- &7Executes a Judgement Day." + - "" + - "&c/verbose &8- &7Turn on and off verbose notifications." + - "&c/alerts &8- &7Turn on and off cheat alerts." + - "" + - "&c/logs (player) (page) &8- &7Read a player's violations." + - "&c/punishlogs (player) &8- &7Check a player's punishments" + - "&7&m---»--*-------------------------------------*--«---" + ban: + # The commands that will be executed when /vulcan ban (player) is executed + commands: + - 'ban %player% &c[Vulcan] Unfair Advantage' + # The messages that will be broadcast when /vulcan ban (player) is executed + broadcast: + - "&7&m---»--*-------------------------------------*--«---" + - "&cVulcan &7has detected &c%player% &7to be cheating and has removed them from the network." + - "&7&m---»--*-------------------------------------*--«---" + # Options for the /vulcan profile (name) command + profile: + - "&7&m---»--*-------------------------------------*--«---" + - "&cVulcan Profile for %player%:" + - " &8» &7%uuid%" + - "" + - "&7Version: &c%client-version%" + - "&7Client Brand: &c%client-brand%" + - "&7Sensitivity: &c%sensitivity%%" + - "&7Last CPS: &c%cps% CPS" + - "" + - "&7Total Violations (&c%total-violations%&7):" + - " &8» &7Combat: &c%combat-violations%" + - " &8» &7Movement: &c%movement-violations%" + - " &8» &7Player: &c%player-violations%" + - "" + - "&7Collisions:" + - "&8» &7Nearby Blocks: %nearby-blocks%" + - "&8» &7Nearby Entities: %nearby-entities%" + - "" + - "&7Potion Effects: %potion-effects%" + - "&7&m---»--*-------------------------------------*--«---" + cps: "%prefix% &7Last CPS for &c%player%&7: &c%cps%" + connection: + - "&7&m---»--*-------------------------------------*--«---" + - "&cConnection Information for %player%:" + - "" + - "&7Transaction Ping: &c%transaction-ping%ms" + - "&7KeepAlive Ping: &c%keepalive-ping%ms" + - "" + - "&7Last Replied Transaction: &c%last-replied-transaction%ms ago" + - "&7Queued Transactions: &c%queued-transactions%" + - "" + - "&7Flying Delay: &c%flying-delay%ms" + - "&7&m---»--*-------------------------------------*--«---" + logs: + color: '&7' + header-footer: '&7&m---»--*--&r&7[ Logs for &c%player% &7(&c%page%&8/&c%max-pages%&7) &7]&7&m--*--«---' + top: + - "&7&m---»--*-------------------------------------*--«---" + - "&cTop Total Violations:" + - " &8- &7%total-1-name% &7(&c%total-1-violations% VL&7)" + - " &8- &7%total-2-name% &7(&c%total-2-violations% VL&7)" + - " &8- &7%total-3-name% &7(&c%total-3-violations% VL&7)" + - " &8- &7%total-4-name% &7(&c%total-4-violations% VL&7)" + - " &8- &7%total-5-name% &7(&c%total-5-violations% VL&7)" + - "" + - "&cTop Combat Violations:" + - " &8- &7%combat-1-name% &7(&c%combat-1-violations% VL&7)" + - " &8- &7%combat-2-name% &7(&c%combat-2-violations% VL&7)" + - " &8- &7%combat-3-name% &7(&c%combat-3-violations% VL&7)" + - " &8- &7%combat-4-name% &7(&c%combat-4-violations% VL&7)" + - " &8- &7%combat-5-name% &7(&c%combat-5-violations% VL&7)" + - "" + - "&cTop Movement Violations:" + - " &8- &7%movement-1-name% &7(&c%movement-1-violations% VL&7)" + - " &8- &7%movement-2-name% &7(&c%movement-2-violations% VL&7)" + - " &8- &7%movement-3-name% &7(&c%movement-3-violations% VL&7)" + - " &8- &7%movement-4-name% &7(&c%movement-4-violations% VL&7)" + - " &8- &7%movement-5-name% &7(&c%movement-5-violations% VL&7)" + - "" + - "&cTop Player Violations:" + - " &8- &7%player-1-name% &7(&c%player-1-violations% VL&7)" + - " &8- &7%player-2-name% &7(&c%player-2-violations% VL&7)" + - " &8- &7%player-3-name% &7(&c%player-3-violations% VL&7)" + - " &8- &7%player-4-name% &7(&c%player-4-violations% VL&7)" + - " &8- &7%player-5-name% &7(&c%player-5-violations% VL&7)" + - "&7&m---»--*-------------------------------------*--«---" + jday: + list-header-footer: "&7&m---»--*-------------------------------------*--«---" + list-format: " &8- &7%name%" + punishlogs: + header-footer: '&7&m---»--*--&r&7[ Punishment Logs for &c%player% &7]&7&m--*--«---' + +punishment-statistics-broadcast: + # Whether or not Vulcan should broadcast how many players it has punished. + enabled: false + # The interval at which the message should be broadcasted in (in ticks) (default = 18000 = 15min) + interval: 18000 + # The message that should be broadcasted + broadcast: + - '&7&m---»--*-------------------------------------*--«---' + - '&7In the past 7 days, &cVulcan &7has punished &c%amount% &7players.' + - '&7&m---»--*-------------------------------------*--«---' + +# Some simple settings +settings: + # Whether or not alerts will automatically be enabled on-join for players who have the permission "vulcan.alerts" + toggle-alerts-on-join: true + # Whether or not the severity placeholder should be based off of per-check violations or the total violations of the player + per-check-severities: true + # Whether or not cinematic mode will be checked for certain aim checks. This isn't really a big deal and can be + # left disabled as this will pretty much NEVER happen unless done intentionally. Enabling this will slow + # detection speeds for certain checks. + cinematic: false + # This is just here in case I forget to remove a debug message when I post an update. If I forget to remove a debug + # message and you see [Vulcan Debug] on your server, disable this (it won't effect you if this is enabled or disabled + # unless I forget to remove a debug message, but if you see [Vulcan Debug] in chat, then set this to false and reload). + debug: true + # Whether or not 'A new update is available!' message will be set on join for players with 'vulcan.admin' permission + check-for-updates: true + # A setting for PacketEvents, we may ask you to change this if you're having issues injecting. If everything is working + # fine, don't touch this. + inject-early: true + # This is the time (in ticks - 20 ticks per second - default value is 80 (4 seconds)) of how long players should be exempt from certain + # checks after velocity gets applied to them via another plugin or something (such as Launchpads, crate plugins, etc etc). + max-velocity-ticks: 50 + # This is the max file size (in KB) before the violations.txt should be zipped and put into the logs folder + max-logs-file-size: 7500 + # If you have a bungee network and want to have a specific server name for punishment/alert messages, etc + server-name: 'Default' + # Whether or not alert messages should be sent on the main thread or asynchronously. If your server is on bungee, it is recommended to keep this + # disabled as sending large chat component messages with so much info (hover, click commands, etc) like the alert commands can + # sometimes cause people to be kicked for 'The server you were on has went down' or something. + # TLDR: + # - Bungeecord Networks: leave this FALSE + # - Single servers: set this to TRUE to save some performance + async-alerts: false + # Whether or not the API should be enabled. If you want to hook into Vulcan and do anything fancy, then enable this, however + # the majority of people will never use this and disabling it allows for less runnables and more performance as the events dont + # need to be called at all (they are also forced to be called sync, so this is a win win performance gain) + enable-api: false + # Whether or not the update checker should be enabled + update-checker: true + # The delay in milliseconds (1000ms = 1 second) + punishment-delay: 10000 + # Whether or not Vulcan should automatically ignore Bedrock players using Floodgate's API. + ignore-floodgate: true + # This is highly highly recommended to keep false as it can be spoofed by the client, however, if you're using Geyser and + # for whatever reason can't get Floodgate to work, then enable this. If you have floodgate-bukkit on your server + # and Geyser is working fine, then don't touch this. + ignore-flags-geyser-client-brand: false + # How long we should wait for everything to initialize before players start being checked (in milliseconds). Default + # value is 2500ms. + join-check-wait-time: 2500 + # Whether or not players with UUID's starting with '000000' should be ignored and not flagged - used for exemptions of + # Geyser players if all else fails. + ignore-geyser-uuids: true + # Whether or not we should ignore flags for players whose usernames start with a certain character/string of characters + ignore-geyser-prefixes: true + # The string to be ignored - all players names who start with a * will not be flagged (case sensitive if not symbols) + ignore-geyser-prefix: "*" + # The max violation (violations above this won't be sent) + max-alert-violation: 250 + # How long should people be exempt from checks when they were in /fly (default = 40 ticks, 2 seconds) + flight-cooldown: 40 + # What the /vulcan top command should display if there aren't enough users for it to sort + top-command-unresolved: "Unresolved" + # Whether or not players who are in the judgement day queue should be able to be banned again. + ignore-if-in-judgement-day: false + # Whether or not players who join with Vivecraft should be ignored. Be careful with this as it can be spoofed. + ignore-vivecraft: false + # Scaffolding are really broken blocks, whether or not we should be more lenient for them for certain checks. + lenient-scaffolding: true + # Whether or not bStats should be loaded + bstats: true + # Whether or not Vulcan should account for entity collisions + entity-collision: true + # Whether or not Vulcan should hook into mcMMO if it is available. + hook-mcmmo: true + # Whether or not Vulcan should hook into MythicMobs if it is available. + hook-mythicmobs: true + # Whether or not Vulcan should hook into GSit if it is available + hook-gsit: true + # Whether or not Vulcan should hook with Brewery if available + hook-brewery: true + # Whether or not Vulcan should ignore alerts for violations which are greater than the max violations threshold + ignore-alerts-over-max-violations: false + # The amount greater than the max violations that should be ignored (example, 3 would mean that if the max violations + # was set to 10, alerts greater than VL 13 would be ignored) + ignore-alerts-over-max-violations-amount: 3 + # Whether or not Vulcan should warn you if you may be using an incompatible spigot fork. + incompatability-manager: true + # Whether or not Vulcan should send plugin messages + plugin-messaging: true + # Whether or not Vulcan should setback players when they are lower than their last onGround position (this can lead to + # things such as anti-voids, so not particularly recommended if you have something like a SkyWars/BedWars server) + dont-setback-lower-positions: false + # Minimum ticks existed before a player is chcked, similar to join-check-wait-time above + min-ticks-existed: 3 + # Whether or not we should calculate the distance between the player and WorldBorder to prevent false flags in the + # Velocity checks. Only needed on very specific servers. + velocity-world-border: false + # Whether or not Vulcan should account for having 10 kabillion entities in one place that launches you very fast and could + # 'false' some checks. Will not matter on 99% of servers + entity-cram-fix-enabled: false + # The amount of entities that should be accounted for + entity-cram-entities-amount: 10 + # How long the checks should be exempted for if the above entities are encountered + entity-cram-exempt-ticks: 30 + +hooks: + ###################################################################################################################### + # Discord BOT Configuration (THIS IS DEPRECATED PLEASE USE THE WEBHOOK BELOW!!!!!!!!!!!!!!!!) # + # enable-hook: Enable/Disable discord BOT support. You must have DiscordBotAPI installed. # + ###################################################################################################################### + discord: + enable-hook: false + alerts-channel-id: 'channel_id_here' + punishment-channel-id: 'channel_id_here' + command-prefix: '!vulcan' + alerts-format: + color: 'ORANGE' + title: 'Vulcan Alert' + description: '%player% failed %check% (Type: %type%) (VL:%vl%)' + image: 'https://crafatar.com/avatars/%uuid%' + content: + - 'Info|%info%|false' + - 'Location|%world% - X:%x%, Y:%y%, Z:%z%|false' + - 'Client Version|%client-version%|false' + - 'Client Brand|%client-brand%|false' + - 'Client Ping|%ping%|false' + - 'Server TPS|%tps%|false' + punishment-format: + color: 'RED' + title: 'Vulcan Punishment' + description: '%player% was punished for %check% (Type: %type%) (VL:%vl%)' + image: 'https://crafatar.com/avatars/%uuid%' + ###################################################################################################################### + # Discord WEBHOOK Configuration # + ###################################################################################################################### +discord-webhook: + # The section for the Discord Webhook alerts + alerts: + # Whether or not Discord Webhook Alerts should be enabled + enabled: false + # Paste the URL to your webhook here. For how to create a webhook, please see https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks + url: 'insert-webhook-url-here' + # The avatar for the webhook + avatar: 'https://i.imgur.com/JPG1Kwk.png' + # Thumbnail for the webhook + thumbnail: 'http://cravatar.eu/avatar/%name%/64.png' + # Colors for the webhook (use a website like https://www.rapidtables.com/web/color/RGB_Color.html to pick colors) + color-r: 252 + color-g: 140 + color-b: 3 + # Username of the webhook + username: 'Vulcan' + # Title of the webhook + title: 'Vulcan Alert' + # Description of the webhook + description: '**%player%** failed %check% %dev%(Type %type%)%dev% [%vl%/%max-vl%]' + # Content will send text outside of the embed, so you can tag roles or people for example. + content: '' + information-field: false + client-version-field: true + client-brand-field: true + server-name-field: false + description-field: false + location-field: true + ping-tps-field: true + punishments: + # Same settings and explanations as above + enabled: false + url: 'insert-webhook-url-here' + avatar: 'https://i.imgur.com/JPG1Kwk.png' + thumbnail: 'http://cravatar.eu/avatar/%name%/64.png' + color-r: 255 + color-g: 0 + color-b: 0 + username: 'Vulcan' + title: 'Vulcan Punishment' + description: '**%player%** was punished for %check% (Type %type%) [VL: %vl%]' + content: '' + description-field: false + server-name-field: false + client-brand-field: false + client-version-field: false + ping-tps-field: false + location-field: false + +######################################################################################################################## +# AbstractCheck Configuration. Almost all of these options are editable live in game via /vulcan gui +# enabled: Whether or not the check is enabled or disabled +# punishable: Whether or not the commands will be executed when the max-violations is reached +# broadcast-punishment: Whether or not the punishment broadcast (found above) should be sent when the max-violations is reached +# max-violations: The max violations threshold; when this is hit, the punishment-commands will be executed (if punishable is set to true) +# alert-interval: How often alerts for this check will be sent, for example, 2 will only send alerts for VL 2, 4, 6, 8, 3 will send alerts +# for violations 3, 6, 9, 12, etc. If you want to reduce the spam in the chat, then you can use this. +# dont-alert-until: This will make it so that only alerts greater than this value are sent. For example, if you set this to 6, +# then only alerts 6 and higher would be sent (anything less than that is still logged, but not sent to staff) +# maximum-ping: 100000 is the default value and your ping can't go higher than this without being kicked for KeepAlive timeout. +# You won't really ever need to change this as ping doesn't really effect any checks and this can open the possibility +# of bypasses with ping spoof, however, the option is here nonetheless. +# minimum-tps: If the TPS is lower than this value, the check won't fire. +# +# buffer: +# max: Buffer is how many times the player needs to 'fail' the check in order to actually alert. This is basically how +# sensitive the check is. I recommend keeping these as default, but if you want the anticheat to be a little more +# sensitive or less sensitive you can play with them a little. Don't set them too low or too high or else there will be +# too many false flags or it just won't flag at all. +# multiple: This is what the buffer gets multiplied by after an alert is sent. For example, if you set it to 1, then it wouldn't +# do anything since (1 * x) is just x. You can also change this if you want alerts to happen slower, for example +# setting it to 0 would make it so when a player reaches the max buffer of 5 for example, their buffer is set to 0 +# instead of 2.5 (as it would be if the multiple was .5 and not 0. +# decay: How much the buffer should decay if the player doesn't fail the check. Again, don't really touch this if you don't +# know what you're doing as you can cause checks to either not flag at all or false positive a lot. You need to have a +# balanced ratio of increasing buffers and decaying the buffer. What we mean by this is that having the decay as 1 +# and increasing the buffer by 1 isn't really balanced as you can just cheat for a tick and then not do anything and +# you will bypass. On the other hand, a buffer decay of .1 against an increase of one is much more balanced as it ensures +# that people who constantly fail the checks will continue to alert and be punished yet any little errors will be +# filtered out and not alert. +# hotbar-shuffle: +# enabled: Whether or not this feature will be enabled. For me.frep.vulcan.spigot.check.impl.combat checks, if the player is failing the check, this will +# shuffle around the item in their hand. Funny to watch as they try to frantically figure out what's going on +# minimum-vl-to-shuffle: The minimum violations that a player has to be at in order for this feature to function. +# shuffle-every: Interval at which this feature will be executed. +# +# random-rotation: +# enabled: Whether or not this feature will be enabled. When players fail me.frep.vulcan.spigot.check.impl.combat checks, their head will be thrown around +# to random locations. Again, pretty funny to watch. +# minimum-vl-to-randomly-rotate: Minimum violations which the player needs to be at in order for this feature to work. +# rotate-every: Interval at which this will be executed. +# For any questions on configuration, please join our Discord or send me on a pm! https://discord.gg/SCNuwUG | frap#0002 +######################################################################################################################## +checks: + combat: + aim: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 3 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .75 + decay: .5 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + b: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 8 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 6 + multiple: .5 + decay: .65 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + c: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 5 + multiple: .5 + decay: .75 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + d: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 10 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 8 + multiple: .5 + decay: .75 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + e: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 3 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .75 + decay: .25 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + f: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 10 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 12 + multiple: .5 + decay: .45 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + g: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .5 + decay: .75 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + h: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 10 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 7 + multiple: .5 + decay: .75 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + i: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 10 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 7 + multiple: .5 + decay: .75 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + k: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 6 + multiple: .5 + decay: .25 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + l: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 10 + multiple: .45 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + m: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 3 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 2 + multiple: .4 + decay: .25 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + n: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 10 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 5 + multiple: .5 + decay: .5 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + o: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 10 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 5 + multiple: .5 + decay: .25 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + p: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 2 + multiple: .4 + decay: .25 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + q: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 6 + multiple: .5 + decay: .25 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + r: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 20 + multiple: .3 + decay: .5 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + s: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 20 + multiple: .25 + decay: .5 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + u: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 1 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + w: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 20 + multiple: .25 + decay: .125 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + x: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 12 + multiple: .25 + decay: .125 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + y: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + autoblock: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 3 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + b: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 3 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + c: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 3 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 2 + multiple: .5 + decay: .5 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + d: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 3 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + # AutoClicker checks not really recommended for banning since you can't ever be 100% certain, if you crank up + # the violations you should be fine but it's all just probability / statistics. + autoclicker: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + max-cps: 25 + b: + enabled: true + punishable: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 25 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .5 + decay: .5 + c: + enabled: true + punishable: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 25 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .5 + decay: 1 + d: + enabled: true + punishable: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 25 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .5 + decay: .5 + e: + enabled: true + punishable: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 25 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .5 + decay: .75 + f: + enabled: true + punishable: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 25 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .5 + decay: 1.25 + g: + enabled: true + punishable: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 25 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 5 + multiple: .25 + decay: 1.25 + h: + enabled: true + punishable: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 25 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .5 + decay: 1 + i: + enabled: true + punishable: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 25 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 5 + multiple: .5 + decay: 1.25 + j: + enabled: true + punishable: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 25 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .5 + decay: 1.25 + k: + enabled: true + punishable: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 25 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .5 + decay: .75 + l: + enabled: true + punishable: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 25 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .25 + decay: 1 + m: + enabled: true + punishable: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 25 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .25 + decay: .75 + n: + enabled: true + punishable: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 25 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 25 + multiple: .15 + decay: .75 + o: + enabled: true + punishable: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 25 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 5 + multiple: .25 + decay: 1.25 + p: + enabled: true + punishable: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 25 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 2 + multiple: .25 + q: + enabled: true + punishable: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 25 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 35 + multiple: .3 + decay: 2.0 + r: + enabled: true + punishable: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 25 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 50 + multiple: .15 + decay: 10 + s: + enabled: true + punishable: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 25 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 30 + multiple: .15 + decay: .825 + t: + enabled: true + punishable: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 25 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 25 + multiple: .15 + decay: .75 + min-kurtosis: 13 + reach: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 8 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .25 + decay: .035 + max-reach: 3.03 + b: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 6 + multiple: .25 + decay: .225 + max-reach: 3.15 + fastbow: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .5 + decay: .125 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + criticals: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 10 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 1 + multiple: .5 + decay: .05 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + b: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 10 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 1 + multiple: .5 + decay: .05 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + killaura: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 4 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .5 + decay: .5 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + b: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 4 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 5 + multiple: .6 + decay: .5 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + c: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 4 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 2 + multiple: .5 + decay: .25 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + d: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 2 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + f: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 4 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 10 + multiple: .25 + decay: 2 + g: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .5 + decay: .05 + h: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 4 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + j: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 10 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 1 + multiple: .5 + decay: .5 + k: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 10 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .5 + decay: .75 + l: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 5 + multiple: .6 + decay: .5 + hotbar-shuffle: + enabled: false + minimum-vl-to-shuffle: 2 + shuffle-every: 2 + random-rotation: + enabled: false + minimum-vl-to-randomly-rotate: 2 + rotate-every: 2 + hitbox: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 10 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .25 + decay: .125 + max-angle: .42 + b: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 6 + multiple: .25 + decay: .125 + max-angle: 45 + velocity: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .25 + decay: .075 + b: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .35 + decay: .125 + c: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 5 + multiple: .25 + decay: .175 + d: + enabled: false + punishable: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .25 + decay: .05 + movement: + noslow: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .25 + decay: .15 + b: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 7 + multiple: .25 + decay: .075 + c: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 7 + multiple: .25 + decay: .15 + d: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 7 + multiple: .25 + decay: .15 + e: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 7 + multiple: .25 + decay: .15 + motion: + a: + enabled: true + punishable: true + setback: false + min-vl-to-setback: 1 + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .25 + decay: .25 + b: + enabled: true + punishable: true + setback: false + min-vl-to-setback: 1 + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .25 + decay: .25 + c: + enabled: true + punishable: true + setback: false + min-vl-to-setback: 1 + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 1 + multiple: .5 + decay: .05 + d: + enabled: true + punishable: true + setback: false + min-vl-to-setback: 1 + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .25 + decay: .05 + e: + enabled: true + punishable: true + setback: false + min-vl-to-setback: 1 + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 3 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 1 + multiple: .5 + decay: .05 + g: + enabled: true + punishable: true + setback: false + min-vl-to-setback: 1 + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 20 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 2 + multiple: .25 + decay: .15 + h: + enabled: false + punishable: true + setback: false + min-vl-to-setback: 1 + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 20 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .25 + decay: .15 + jump: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + setback: false + min-vl-to-setback: 1 + broadcast-punishment: false + max-violations: 25 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 2 + multiple: .25 + decay: .15 + b: + enabled: true + punishable: true + discord-alert-interval: 1 + setback: false + min-vl-to-setback: 1 + broadcast-punishment: false + max-violations: 25 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 2 + multiple: .25 + decay: .15 + step: + a: + enabled: true + punishable: true + setback: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + b: + enabled: true + punishable: true + setback: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 6 + multiple: .25 + decay: .35 + c: + enabled: true + punishable: true + setback: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .25 + decay: .1 + boatfly: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .33 + decay: .125 + kick-out: false + b: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 5 + multiple: .25 + decay: .25 + kick-out: false + c: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 5 + multiple: .25 + decay: .125 + kick-out: false + entityflight: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 5 + multiple: .5 + decay: .25 + kick-out: false + b: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 5 + multiple: .5 + decay: .25 + antilevitation: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 8 + multiple: .25 + decay: .075 + nosaddle: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 6 + multiple: .5 + decay: .125 + entityspeed: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 5 + multiple: .5 + decay: .25 + kick-out: false + elytra: + a: + enabled: true + punishable: true + setback: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 1 + multiple: .5 + decay: .25 + max-speed: 4.25 + b: + enabled: true + punishable: true + setback: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 8 + multiple: .25 + decay: .125 + c: + enabled: true + punishable: true + setback: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 6 + multiple: .5 + decay: .125 + f: + enabled: true + punishable: true + setback: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 10 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 6 + multiple: .25 + decay: .125 + g: + enabled: true + punishable: false + setback: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 25 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .25 + decay: .1 + i: + enabled: true + punishable: true + setback: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .25 + decay: .1 + k: + enabled: true + punishable: true + setback: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .25 + decay: .1 + l: + enabled: true + punishable: true + setback: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .25 + decay: .1 + m: + enabled: true + punishable: true + setback: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .25 + decay: .1 + speed: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + setback: false + min-vl-to-setback: 1 + broadcast-punishment: false + max-violations: 12 + alert-interval: 1 + dont-alert-until: 2 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 5 + multiple: .35 + decay: .125 + b: + enabled: true + punishable: true + discord-alert-interval: 1 + setback: false + min-vl-to-setback: 1 + broadcast-punishment: false + max-violations: 20 + alert-interval: 1 + dont-alert-until: 2 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .25 + decay: .045 + min-difference: .0025 + c: + enabled: true + punishable: true + discord-alert-interval: 1 + setback: false + min-vl-to-setback: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 2 + dont-alert-until: 2 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .25 + decay: .045 + min-difference: .001 + d: + enabled: true + punishable: true + discord-alert-interval: 1 + setback: false + min-vl-to-setback: 1 + broadcast-punishment: false + max-violations: 20 + alert-interval: 1 + dont-alert-until: 2 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .25 + decay: .045 + min-difference: .0025 + fastclimb: + a: + enabled: true + punishable: true + setback: false + min-vl-to-setback: 1 + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .5 + decay: .125 + wallclimb: + a: + enabled: true + punishable: true + setback: false + min-vl-to-setback: 1 + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .35 + decay: .225 + jesus: + a: + enabled: true + punishable: true + setback: false + min-vl-to-setback: 1 + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 2 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .5 + decay: .025 + b: + enabled: true + punishable: true + setback: false + min-vl-to-setback: 1 + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 2 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .5 + decay: .175 + c: + enabled: true + punishable: true + setback: false + min-vl-to-setback: 1 + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 2 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 10 + multiple: .45 + decay: .75 + d: + enabled: true + punishable: true + setback: false + min-vl-to-setback: 1 + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .45 + decay: .175 + e: + enabled: true + punishable: true + setback: false + min-vl-to-setback: 1 + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 2 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 10 + multiple: .25 + decay: .175 + flight: + a: + enabled: true + punishable: true + discord-alert-interval: 5 + setback: false + min-vl-to-setback: 1 + broadcast-punishment: false + max-violations: 30 + alert-interval: 2 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .65 + decay: .275 + # Whether or not this check should be disabled for suspected ghost blocks - enabling this will make these checks prone + # to be bypasses by certain fly modules which spoof onGround values as if the player were on a ghost block, so if you enable + # this make sure to enable setbacks for ghost-blocks in the ghost-blocks-fix section. + ignore-ghost-blocks: true + b: + enabled: true + punishable: true + discord-alert-interval: 5 + setback: false + min-vl-to-setback: 1 + broadcast-punishment: false + max-violations: 30 + alert-interval: 2 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .5 + decay: .275 + c: + enabled: true + punishable: true + discord-alert-interval: 5 + setback: false + min-vl-to-setback: 1 + broadcast-punishment: false + max-violations: 30 + alert-interval: 2 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .75 + decay: .225 + # Whether or not this check should be disabled for suspected ghost blocks - enabling this will make these checks prone + # to be bypasses by certain fly modules which spoof onGround values as if the player were on a ghost block, so if you enable + # this make sure to enable setbacks for ghost-blocks in the ghost-blocks-fix section. + ignore-ghost-blocks: true + d: + enabled: true + punishable: true + discord-alert-interval: 5 + setback: false + min-vl-to-setback: 1 + broadcast-punishment: false + max-violations: 30 + alert-interval: 2 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .35 + decay: .275 + # Whether or not this check should be disabled for suspected ghost blocks - enabling this will make these checks prone + # to be bypasses by certain fly modules which spoof onGround values as if the player were on a ghost block, so if you enable + # this make sure to enable setbacks for ghost-blocks in the ghost-blocks-fix section. + ignore-ghost-blocks: true + e: + enabled: true + punishable: true + discord-alert-interval: 5 + setback: false + min-vl-to-setback: 1 + broadcast-punishment: false + max-violations: 30 + alert-interval: 2 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .4 + decay: .5 + # Whether or not this check should be disabled for suspected ghost blocks - enabling this will make these checks prone + # to be bypasses by certain fly modules which spoof onGround values as if the player were on a ghost block, so if you enable + # this make sure to enable setbacks for ghost-blocks in the ghost-blocks-fix section. + ignore-ghost-blocks: true + vclip: + a: + enabled: true + punishable: false + setback: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 20 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + sprint: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 6 + multiple: .25 + decay: .4 + strafe: + a: + enabled: true + punishable: true + setback: false + min-vl-to-setback: 1 + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 2 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 2 + multiple: .5 + decay: .05 + b: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .15 + decay: .075 + player: + fastuse: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + fastplace: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + max-blocks: 15 + b: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 1 + multiple: .25 + decay: .5 + max-blocks: 4 + fastbreak: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 2 + multiple: .25 + decay: .5 + min-difference: -125 + tower: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .5 + decay: .75 + scaffold: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 3 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + b: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 10 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .25 + decay: .25 + c: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 2 + multiple: .25 + decay: .5 + d: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 10 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .25 + decay: .5 + e: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 10 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .25 + decay: .5 + f: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 3 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .5 + decay: .1 + g: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 2 + multiple: .25 + decay: .25 + h: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 8 + multiple: .25 + decay: .35 + i: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 10 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + j: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + k: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 1 + multiple: .5 + decay: .35 + max-blocks: 6 + m: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 12 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 1 + multiple: .5 + decay: .25 + n: + enabled: false + punishable: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 12 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .5 + decay: .25 + timer: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 2 + dont-alert-until: 3 + maximum-ping: 100000 + minimum-tps: 19.8 + punishment-commands: + - 'minecraft:kick %player% Internal Exception: io.netty.handler.timeout.ReadTimeoutException' + buffer: + max: 35 + multiple: .425 + decay: 1.85 + max-speed: 1.05 + d: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 35 + alert-interval: 2 + dont-alert-until: 8 + maximum-ping: 100000 + minimum-tps: 19.8 + punishment-commands: + - 'minecraft:kick %player% Internal Exception: io.netty.handler.timeout.ReadTimeoutException' + buffer: + max: 3 + multiple: .5 + decay: .25 + max-balance: 75 + baritone: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 20 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 20 + multiple: .5 + decay: .25 + b: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 20 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 2 + multiple: .5 + decay: .05 + ghosthand: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 3 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + cancel: true + airplace: + a: + enabled: false + punishable: false + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 10 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + badpackets: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 3 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 2 + multiple: .5 + decay: .25 + b: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 1 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + c: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 1 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + d: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .25 + decay: .01 + e: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 1 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + f: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 1 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + g: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 3 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + h: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 3 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + i: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 3 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + j: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 3 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + k: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .5 + decay: .4 + m: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 5 + multiple: .33 + decay: .25 + n: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 10 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 20 + multiple: .25 + decay: 2.5 + o: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 1 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .5 + decay: .15 + p: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 10 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .5 + decay: .15 + q: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 1 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .5 + decay: .15 + r: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 10 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 6 + multiple: .5 + decay: .25 + s: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + t: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 1 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + u: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 1 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + v: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 8 + multiple: .5 + decay: .075 + kick-out: false + w: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 10 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 8 + multiple: .5 + decay: .75 + x: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 10 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 6 + multiple: .5 + decay: .35 + y: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 1 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + z: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 3 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + 1: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 12 + multiple: .25 + decay: .25 + 2: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 12 + multiple: .25 + decay: .25 + 4: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .25 + decay: .025 + 5: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + inventory: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 2 + multiple: .25 + decay: .25 + b: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 2 + multiple: .25 + decay: .25 + invalid: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + setback: false + min-vl-to-setback: 1 + broadcast-punishment: false + max-violations: 8 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 2 + multiple: .25 + decay: .05 + c: + enabled: true + punishable: true + discord-alert-interval: 1 + setback: false + min-vl-to-setback: 1 + broadcast-punishment: false + max-violations: 8 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .25 + decay: .045 + d: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 10 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 8 + multiple: .25 + decay: .5 + e: + enabled: true + punishable: true + discord-alert-interval: 1 + setback: false + min-vl-to-setback: 1 + broadcast-punishment: false + max-violations: 8 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 1 + multiple: .5 + decay: .01 + f: + enabled: true + punishable: true + discord-alert-interval: 1 + setback: false + min-vl-to-setback: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 1 + multiple: .5 + decay: .01 + g: + enabled: true + punishable: true + discord-alert-interval: 1 + setback: false + min-vl-to-setback: 1 + broadcast-punishment: false + max-violations: 20 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 2 + multiple: .5 + decay: .025 + h: + enabled: true + punishable: true + discord-alert-interval: 1 + setback: false + min-vl-to-setback: 1 + broadcast-punishment: false + max-violations: 20 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .5 + decay: .05 + i: + enabled: true + punishable: true + discord-alert-interval: 1 + setback: false + min-vl-to-setback: 1 + broadcast-punishment: false + max-violations: 20 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 3 + multiple: .5 + decay: .05 + j: + enabled: true + punishable: true + discord-alert-interval: 1 + setback: false + min-vl-to-setback: 1 + broadcast-punishment: false + max-violations: 20 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 1 + multiple: .5 + decay: .05 + groundspoof: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .5 + decay: .125 + b: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 5 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .5 + decay: .125 + c: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 15 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + buffer: + max: 4 + multiple: .5 + decay: .125 + improbable: + a: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 1 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + max-combat-violations: 25 + b: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 1 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + max-movement-violations: 30 + c: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 1 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + max-player-violations: 30 + d: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 1 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + max-autoclicker-violations: 30 + e: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 1 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + max-total-violations: 50 + f: + enabled: true + punishable: true + discord-alert-interval: 1 + broadcast-punishment: false + max-violations: 1 + alert-interval: 1 + dont-alert-until: 1 + maximum-ping: 100000 + minimum-tps: 19.0 + punishment-commands: + - 'kick %player% &c[Vulcan] Unfair Advantage' + max-scaffold-violations: 25 \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..5e6c78a --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,27 @@ +name: Vulcan +version: "2.6.7-HOTFIX" +main: me.frep.vulcan.spigot.VulcanPlugin +api-version: 1.13 +authors: [frep, GladUrBad, Joshb_, Elevated, retrooper, "5170"] +description: Vulcan Cheat Detection +softdepend: [DiscordBotAPI, PlaceholderAPI, ViaVersion, mcMMO, MythicMobs, CrackShot, LibsDisguises, floodgate, GSit, ProtocolSupport] + +commands: + alerts: + description: Toggle on and off Vulcan's alert messages. + usage: / + verbose: + description: Toggle on and off Vulcan's verbose messages. + usage: / + vulcan: + description: Vulcan's main command. + usage: / + jday: + description: Manage Vulcan's Judgement Day feature. + usage: / + logs: + description: In-game violations.txt access. + usage: / + punishlogs: + description: In-game punishments.txt access. + usage: / diff --git a/src/main/resources/stats.yml b/src/main/resources/stats.yml new file mode 100644 index 0000000..2b863a8 --- /dev/null +++ b/src/main/resources/stats.yml @@ -0,0 +1 @@ +punishments: 0 \ No newline at end of file