Adding API, new checks, false positive fixes

- New Order (Place) and Order (Use) check
- New Autoclicker (A) and Autoclicker (B) check.
- Event system for checks has changed to use lambdas instead of reflection (IE WAction and TimedWAction)
- Added configurable commands for punishments
- Added punishments
- Added title command (wont show in help menu)
- Added new AnticheatAPI project
- Implemented flag, punish, and cancel listeners for API uses.
This commit is contained in:
Dawson
2022-08-23 10:18:14 -04:00
parent bd50501640
commit 49391bfea9
42 changed files with 581 additions and 115 deletions
+62
View File
@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>dev.brighten.ac</groupId>
<artifactId>API</artifactId>
<version>1.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<repositories>
<repository>
<id>funkemunky-releases</id>
<url>https://nexus.funkemunky.cc/content/repositories/releases/</url>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>8</source>
<target>8</target>
<compilerArgument>-XDignore.symbol.file</compilerArgument>
<useIncrementalCompilation>false</useIncrementalCompilation>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.github.spigot</groupId>
<artifactId>1.8.8</artifactId>
<version>1.8.8</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,45 @@
package dev.brighten.ac.api;
import dev.brighten.ac.api.event.AnticheatEvent;
import org.bukkit.plugin.Plugin;
import java.util.*;
public class AnticheatAPI {
public static AnticheatAPI INSTANCE;
private final Map<String, List<AnticheatEvent>> registeredEvents = new HashMap<>();
public AnticheatAPI() {
INSTANCE = this;
}
public void registerEvent(Plugin plugin, AnticheatEvent event) {
registeredEvents.compute(plugin.getName(), (key, list) -> {
if(list == null) {
list = new ArrayList<>();
}
list.add(event);
return list;
});
}
public void unregisterEvents(Plugin plugin) {
registeredEvents.remove(plugin.getName());
}
public List<AnticheatEvent> getAllEvents() {
final List<AnticheatEvent> allEvents = new ArrayList<>();
synchronized (registeredEvents) {
for (List<AnticheatEvent> events : registeredEvents.values()) {
allEvents.addAll(events);
}
}
allEvents.sort(Comparator.comparing(e -> e.priority().getSlot()));
return allEvents;
}
}
@@ -1,7 +1,8 @@
package dev.brighten.ac.check;
package dev.brighten.ac.api.check;
public enum CheckType {
COMBAT,
AUTOCLICKER,
MOVEMENT,
BLOCK,
INTERACT,
@@ -0,0 +1,9 @@
package dev.brighten.ac.api.check;
public interface ECheck {
String getName();
float getVl();
CheckType getCheckType();
}
@@ -0,0 +1,24 @@
package dev.brighten.ac.api.event;
import dev.brighten.ac.api.check.ECheck;
import dev.brighten.ac.api.event.result.CancelResult;
import dev.brighten.ac.api.event.result.FlagResult;
import dev.brighten.ac.api.event.result.PunishResult;
import org.bukkit.entity.Player;
import org.bukkit.event.EventPriority;
import java.util.List;
public interface AnticheatEvent {
PunishResult onPunish(Player player, ECheck check, List<String> commands, boolean cancelled);
FlagResult onFlag(Player player, ECheck check, String information, boolean cancelled);
CancelResult onCancel(Player player, ECheck check, boolean cancelled);
EventPriority priority();
}
@@ -0,0 +1,10 @@
package dev.brighten.ac.api.event.result;
import lombok.Builder;
import lombok.Getter;
@Builder
@Getter
public class CancelResult {
private final boolean cancelled;
}
@@ -0,0 +1,10 @@
package dev.brighten.ac.api.event.result;
import lombok.Builder;
import lombok.Getter;
@Getter
@Builder
public class FlagResult {
private final boolean cancelled;
}
@@ -0,0 +1,14 @@
package dev.brighten.ac.api.event.result;
import lombok.Builder;
import lombok.Getter;
import java.util.List;
@Builder
@Getter
public class PunishResult {
private final boolean cancelled;
private String broadcastMessage;
private List<String> commands;
}
+6
View File
@@ -105,6 +105,12 @@
<version>1.8.8</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>dev.brighten.ac</groupId>
<artifactId>API</artifactId>
<version>1.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.github.spigot</groupId>
<artifactId>1.7.10</artifactId>
+24 -6
View File
@@ -3,11 +3,13 @@ package dev.brighten.ac;
import co.aikar.commands.BaseCommand;
import co.aikar.commands.BukkitCommandManager;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import dev.brighten.ac.api.AnticheatAPI;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckManager;
import dev.brighten.ac.data.PlayerRegistry;
import dev.brighten.ac.handler.PacketHandler;
import dev.brighten.ac.handler.keepalive.KeepaliveProcessor;
import dev.brighten.ac.handler.protocolsupport.ProtocolAPI;
import dev.brighten.ac.packet.handler.HandlerAbstract;
import dev.brighten.ac.packet.listener.PacketProcessor;
import dev.brighten.ac.utils.*;
@@ -72,14 +74,24 @@ public class Anticheat extends JavaPlugin {
.setUncaughtExceptionHandler((t, e) -> RunUtils.task(e::printStackTrace))
.build());
saveDefaultConfig();
commandManager = new BukkitCommandManager(this);
commandManager.enableUnstableAPI("help");
new CommandPropertiesManager(commandManager, getDataFolder(),
getResource("command-messages.properties"));
this.keepaliveProcessor = new KeepaliveProcessor();
packetProcessor = new PacketProcessor();
new AnticheatAPI();
initializeScanner(getClass(), this,
null,
true,
true);
this.keepaliveProcessor = new KeepaliveProcessor();
this.checkManager = new CheckManager();
this.playerRegistry = new PlayerRegistry();
this.packetHandler = new PacketHandler();
@@ -95,11 +107,6 @@ public class Anticheat extends JavaPlugin {
} catch (Exception e) {
e.printStackTrace();
}
initializeScanner(getClass(), this,
null,
true,
true);
}
public void onDisable() {
@@ -110,12 +117,15 @@ public class Anticheat extends JavaPlugin {
HandlerAbstract.shutdown();
HandlerList.unregisterAll(this);
packetProcessor.shutdown();
packetProcessor = null;
checkManager.getCheckClasses().clear();
Check.alertsEnabled.clear();
Check.debugInstances.clear();
checkManager = null;
keepaliveProcessor.keepAlives.cleanUp();
keepaliveProcessor = null;
ProtocolAPI.INSTANCE = null;
tps = null;
Bukkit.getScheduler().cancelTasks(this);
@@ -129,8 +139,16 @@ public class Anticheat extends JavaPlugin {
} catch (Exception e) {
throw new RuntimeException(e);
}
AnticheatAPI.INSTANCE = null;
onTickEnd.clear();
onTickEnd = null;
packetHandler = null;
}
public void initializeScanner(Class<? extends Plugin> mainClass, Plugin plugin, ClassLoader loader,
boolean loadListeners, boolean loadCommands) {
initializeScanner(mainClass, plugin, loader, ClassScanner.scanFile(null, mainClass), loadListeners,
+66 -6
View File
@@ -1,6 +1,13 @@
package dev.brighten.ac.check;
import dev.brighten.ac.Anticheat;
import dev.brighten.ac.api.AnticheatAPI;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.api.check.ECheck;
import dev.brighten.ac.api.event.AnticheatEvent;
import dev.brighten.ac.api.event.result.CancelResult;
import dev.brighten.ac.api.event.result.FlagResult;
import dev.brighten.ac.api.event.result.PunishResult;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.utils.*;
import dev.brighten.ac.utils.timer.Timer;
@@ -12,16 +19,18 @@ import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Bukkit;
import java.util.*;
import java.util.stream.Collectors;
public abstract class Check {
public class Check implements ECheck {
public final APlayer player;
@Getter
private final CheckData checkData;
@Getter
private int vl;
private float vl;
private long lastFlagRun;
private final Timer lastAlert = new MillisTimer();
@@ -34,6 +43,16 @@ public abstract class Check {
this.checkData = getClass().getAnnotation(CheckData.class);
}
@Override
public String getName() {
return checkData.name();
}
@Override
public CheckType getCheckType() {
return checkData.type();
}
private String formatAlert(String toFormat, String info) {
return addPlaceHolders(Color.translate(toFormat.replace("%desc%", String.join("\n",
MiscUtils
@@ -45,10 +64,20 @@ public abstract class Check {
return string.replace("%player%", player.getBukkitPlayer().getName())
.replace("%check%", checkData.name())
.replace("%name%", player.getBukkitPlayer().getName())
.replace("%p", String.valueOf(player.getLagInfo().getTransPing()))
.replace("%t", String.valueOf(MathUtils.round(Anticheat.INSTANCE.getTps(), 2)))
.replace("%vl%", String.valueOf(MathUtils.round(vl, 1)));
}
public void cancel() {
CancelResult result = CancelResult.builder().cancelled(false).build();
for (AnticheatEvent event : AnticheatAPI.INSTANCE.getAllEvents()) {
result = event.onCancel(player.getBukkitPlayer(), this, result.isCancelled());
}
if(result.isCancelled()) return;
if(checkData.type() == CheckType.COMBAT) {
player.hitsToCancel++;
} else {
@@ -84,6 +113,10 @@ public abstract class Check {
}
public void flag(String information, Object... variables) {
flag(true, information, variables);
}
public void flag(boolean punish, String information, Object... variables) {
vl++;
if(System.currentTimeMillis() - lastFlagRun < 50L) return;
@@ -92,12 +125,18 @@ public abstract class Check {
vl = 0;
lastFlagRun = System.currentTimeMillis();
final String finalInformation = String.format(information, variables);
final String info = String.format(information, variables);
FlagResult currentResult = FlagResult.builder().cancelled(false).build();
for (AnticheatEvent event : AnticheatAPI.INSTANCE.getAllEvents()) {
currentResult = event.onFlag(player.getBukkitPlayer(), this, info,
currentResult.isCancelled());
}
if(currentResult.isCancelled()) return;
boolean dev = Anticheat.INSTANCE.getTps() < 18;
final String info = finalInformation
.replace("%p", String.valueOf(player.getLagInfo().getTransPing()))
.replace("%t", String.valueOf(MathUtils.round(Anticheat.INSTANCE.getTps(), 2)));
//if(vl > 0) Anticheat.INSTANCE.loggerManager.addLog(player, this, info);
//Sending Discord webhook alert
@@ -122,10 +161,31 @@ public abstract class Check {
Anticheat.INSTANCE.getPlayerRegistry().getPlayer(uuid)
.ifPresent(apl -> apl.getBukkitPlayer().spigot().sendMessage(toSend));
}
if(punish && vl > checkData.punishVl()) {
punish();
}
lastAlert.reset();
});
}
public void punish() {
PunishResult result = PunishResult.builder().cancelled(false).build();
List<String> commands = CheckConfig.punishmentCommands.stream().map(this::addPlaceHolders)
.collect(Collectors.toList());
for (AnticheatEvent event : AnticheatAPI.INSTANCE.getAllEvents()) {
result = event.onPunish(player.getBukkitPlayer(),this, commands, result.isCancelled());
}
PunishResult finalResult = result;
RunUtils.task(() -> {
for (String punishmentCommand : finalResult.getCommands()) {
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), punishmentCommand);
}
});
vl = 0;
}
private TextComponent createTxt(String txt) {
return createTxt(txt, "");
}
@@ -0,0 +1,14 @@
package dev.brighten.ac.check;
import dev.brighten.ac.utils.ConfigSetting;
import dev.brighten.ac.utils.Init;
import java.util.Arrays;
import java.util.List;
@Init
public class CheckConfig {
@ConfigSetting(name = "punishments.commands")
public static List<String> punishmentCommands = Arrays.asList("kick %player% Unfair Advantage (%check%)");
}
@@ -1,5 +1,8 @@
package dev.brighten.ac.check;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.packet.ProtocolVersion;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -7,4 +10,9 @@ import java.lang.annotation.RetentionPolicy;
public @interface CheckData {
String name();
CheckType type();
int punishVl() default 10;
ProtocolVersion minVersion() default ProtocolVersion.V1_7;
ProtocolVersion maxVersion() default ProtocolVersion.V1_19;
}
@@ -32,8 +32,8 @@ public class CheckStatic {
private void processClass() {
initConst = checkClass.getConstructor(APlayer.class);
for (WrappedField field : checkClass.getFields()) {
if(!Action.class.isAssignableFrom(field.getType())
|| TimedAction.class.isAssignableFrom(field.getType())) continue;
if(!WAction.class.isAssignableFrom(field.getType())
&& !TimedWAction.class.isAssignableFrom(field.getType())) continue;
Type genericType = field.getField().getGenericType();
Type type = null;
@@ -57,7 +57,7 @@ public class CheckStatic {
continue;
}
if(field.getType().equals(Action.class)) {
if(field.getType().equals(WAction.class)) {
actions.add(new Tuple<>(field, (Class<?>)type));
} else { //This will always be TimedAction
timedActions.add(new Tuple<>(field, (Class<?>)type));
@@ -1,6 +1,6 @@
package dev.brighten.ac.check;
@FunctionalInterface
public interface TimedAction<T> {
public interface TimedWAction<T> {
void invoke(T event, long timestamp);
}
@@ -1,6 +1,6 @@
package dev.brighten.ac.check;
@FunctionalInterface
public interface Action<T> {
public interface WAction<T> {
void invoke(T event);
}
@@ -1,9 +1,9 @@
package dev.brighten.ac.check.impl.combat;
import dev.brighten.ac.check.Action;
import dev.brighten.ac.check.WAction;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckData;
import dev.brighten.ac.check.CheckType;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying;
import dev.brighten.ac.utils.Color;
@@ -22,7 +22,7 @@ public class Aim extends Check {
protected Timer lastGrid = new TickTimer(3);
Action<WPacketPlayInFlying> onFlying = (packet) -> {
WAction<WPacketPlayInFlying> onFlying = (packet) -> {
if(!packet.isLooked()) return;
if(player.getMovement().getYawGcdList().size() < 40) {
@@ -1,9 +1,9 @@
package dev.brighten.ac.check.impl.combat;
import dev.brighten.ac.check.Action;
import dev.brighten.ac.check.WAction;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckData;
import dev.brighten.ac.check.CheckType;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.packet.ProtocolVersion;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying;
@@ -36,7 +36,7 @@ public class Hitbox extends Check {
super(player);
}
Action<WPacketPlayInUseEntity> useEntity = packet -> {
WAction<WPacketPlayInUseEntity> useEntity = packet -> {
if(packet.getAction() == WPacketPlayInUseEntity.EnumEntityUseAction.ATTACK
&& allowedEntityTypes.contains(packet.getEntity(player.getBukkitPlayer().getWorld()).getType())) {
attacks.add(new Tuple<>(packet.getEntity(player.getBukkitPlayer().getWorld()), player.getMovement().getTo().getLoc().clone()));
@@ -46,7 +46,7 @@ public class Hitbox extends Check {
//TODO Figure out how to make the check more sensitive without compromising network stability
//Aka figure out how to minimize the amount of previous locations needed to process to keep network
//stability. like shortening the amount stored, or removing older ones.
Action<WPacketPlayInFlying> onFlying = packet -> {
WAction<WPacketPlayInFlying> onFlying = packet -> {
if(player.getInfo().isCreative() || player.getInfo().isInVehicle()) {
attacks.clear();
return;
@@ -0,0 +1,41 @@
package dev.brighten.ac.check.impl.combat.autoclicker;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckData;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.check.WAction;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.packet.ProtocolVersion;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInArmAnimation;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying;
@CheckData(name = "AutoClicker (A)", type = CheckType.AUTOCLICKER, maxVersion = ProtocolVersion.V1_8_9)
public class AutoclickerA extends Check {
public AutoclickerA(APlayer player) {
super(player);
}
private int flyingTicks, cps;
WAction<WPacketPlayInFlying> flying = (packet) -> {
flyingTicks++;
if(flyingTicks >= 20) {
if(cps > 22) {
if(cps > 30) {
punish();
}
flag("cps=%s", cps);
}
cps = 0;
}
};
WAction<WPacketPlayInArmAnimation> armAnimation = packet -> {
if(!player.getInfo().breakingBlock
&& player.getInfo().getLastBlockDig().isPassed(1)
&& player.getInfo().getLastBlockPlace().isPassed(1)) {
cps++;
}
debug("breaking=%s", player.getInfo().breakingBlock);
};
}
@@ -0,0 +1,34 @@
package dev.brighten.ac.check.impl.combat.autoclicker;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckData;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.check.TimedWAction;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInArmAnimation;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying;
@CheckData(name = "Autoclicker (B)", type = CheckType.AUTOCLICKER)
public class AutoclickerB extends Check {
public AutoclickerB(APlayer player) {
super(player);
}
private long lastFlying;
private int buffer;
TimedWAction<WPacketPlayInFlying> flyingPacket = (packet, timestamp) -> {
if(player.getMovement().getLastTeleport().isPassed(1))
lastFlying = timestamp;
};
TimedWAction<WPacketPlayInArmAnimation> animation = (packet, timestamp) -> {
if(timestamp - lastFlying < 10 && player.getLagInfo().getLastPacketDrop().isPassed(1)) {
if(++buffer > 4) {
flag("delta=%s", timestamp - lastFlying);
}
} else if(buffer > 0) buffer--;
debug("delta=%sms", timestamp - lastFlying);
};
}
@@ -1,9 +1,9 @@
package dev.brighten.ac.check.impl.fly;
import dev.brighten.ac.check.Action;
import dev.brighten.ac.check.WAction;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckData;
import dev.brighten.ac.check.CheckType;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.packet.ProtocolVersion;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying;
@@ -23,7 +23,7 @@ public class FlyA extends Check {
private float buffer;
private static double mult = 0.98f;
Action<WPacketPlayInFlying> flying = packet -> {
WAction<WPacketPlayInFlying> flying = packet -> {
if(!packet.isMoved() || (player.getMovement().getDeltaXZ() == 0
&& player.getMovement().getDeltaY() == 0)) {
return;
@@ -1,9 +1,9 @@
package dev.brighten.ac.check.impl.fly;
import dev.brighten.ac.check.Action;
import dev.brighten.ac.check.WAction;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckData;
import dev.brighten.ac.check.CheckType;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying;
import dev.brighten.ac.utils.timer.Timer;
@@ -18,7 +18,7 @@ public class FlyB extends Check {
private Timer lastNearGround = new TickTimer();
private float buffer;
Action<WPacketPlayInFlying> flying = packet -> {
WAction<WPacketPlayInFlying> flying = packet -> {
if(player.getInfo().isNearGround()) lastNearGround.reset();
if(!packet.isMoved() || player.getInfo().isGeneralCancel()) return;
@@ -1,9 +1,9 @@
package dev.brighten.ac.check.impl.nofall;
import dev.brighten.ac.check.Action;
import dev.brighten.ac.check.WAction;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckData;
import dev.brighten.ac.check.CheckType;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying;
@@ -17,7 +17,7 @@ public class NoFallA extends Check {
private static double divisor = 1. / 64.;
private float buffer;
Action<WPacketPlayInFlying> flying = packet -> {
WAction<WPacketPlayInFlying> flying = packet -> {
if(player.getInfo().isGeneralCancel()
|| (player.getMovement().getDeltaXZ() == 0 && player.getMovement().getDeltaY() == 0)
|| player.getBlockInfo().inLiquid
@@ -1,9 +1,9 @@
package dev.brighten.ac.check.impl.nofall;
import dev.brighten.ac.check.Action;
import dev.brighten.ac.check.WAction;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckData;
import dev.brighten.ac.check.CheckType;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying;
@@ -18,7 +18,7 @@ public class NoFallB extends Check {
private int airBuffer, groundBuffer;
Action<WPacketPlayInFlying> flying = packet -> {
WAction<WPacketPlayInFlying> flying = packet -> {
if(player.getMovement().getLastTeleport().isNotPassed(3)
|| player.getMovement().getMoveTicks() < 2
|| player.getInfo().canFly
@@ -0,0 +1,35 @@
package dev.brighten.ac.check.impl.order;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckData;
import dev.brighten.ac.check.TimedWAction;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInBlockPlace;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying;
@CheckData(name = "Order (Place)", type = CheckType.ORDER, punishVl = 4)
public class Place extends Check {
public Place(APlayer player) {
super(player);
}
private long lastFlying;
private int buffer;
TimedWAction<WPacketPlayInBlockPlace> placePacket = (packet, timestamp) -> {
if(timestamp - lastFlying < 10 && player.getLagInfo().getLastPacketDrop().isPassed(1)) {
if(++buffer > 4) {
buffer = 5;
flag("delta=%sms", timestamp - lastFlying);
}
} else if(buffer > 0) buffer--;
debug("buffer=%s delta=%sms", buffer, timestamp - lastFlying);
};
TimedWAction<WPacketPlayInFlying> flying = (packet, timestamp) -> {
if(player.getMovement().getLastTeleport().isPassed(1))
lastFlying = timestamp;
};
}
@@ -0,0 +1,34 @@
package dev.brighten.ac.check.impl.order;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckData;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.check.TimedWAction;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInUseEntity;
@CheckData(name = "Order (Use)", type = CheckType.ORDER)
public class UseEntity extends Check {
private long lastFlying;
private int buffer;
public UseEntity(APlayer player) {
super(player);
}
TimedWAction<WPacketPlayInUseEntity> useEntity = (packet, timestamp) -> {
if(timestamp - lastFlying < 10 && player.getLagInfo().getLastPacketDrop().isPassed(1)) {
if(++buffer > 5) {
buffer = 6;
flag("delta=%s", timestamp - lastFlying);
}
} else if(buffer > 0) buffer--;
};
TimedWAction<WPacketPlayInFlying> flying = (packet, timestamp) -> {
if(player.getMovement().getLastTeleport().isPassed(0))
lastFlying = timestamp;
};
}
@@ -1,9 +1,9 @@
package dev.brighten.ac.check.impl.speed;
import dev.brighten.ac.check.Action;
import dev.brighten.ac.check.WAction;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckData;
import dev.brighten.ac.check.CheckType;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.packet.ProtocolVersion;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying;
@@ -33,7 +33,7 @@ public class Horizontal extends Check {
super(player);
}
Action<WPacketPlayInFlying> flying = packet -> {
WAction<WPacketPlayInFlying> flying = packet -> {
Block underBlock = BlockUtils.getBlock(player.getMovement().getTo().getLoc()
.toLocation(player.getBukkitPlayer().getWorld())
.subtract(0, 1, 0)),
@@ -1,9 +1,9 @@
package dev.brighten.ac.check.impl.velocity;
import dev.brighten.ac.check.Action;
import dev.brighten.ac.check.WAction;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckData;
import dev.brighten.ac.check.CheckType;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying;
import org.bukkit.util.Vector;
@@ -23,7 +23,7 @@ public class VelocityA extends Check {
});
}
Action<WPacketPlayInFlying> flying = packet -> {
WAction<WPacketPlayInFlying> flying = packet -> {
if(currentVelocity != null && currentVelocity.getY() > 0
&& !player.getBlockInfo().inWeb
&& !player.getBlockInfo().onClimbable
@@ -1,9 +1,9 @@
package dev.brighten.ac.check.impl.velocity;
import dev.brighten.ac.check.Action;
import dev.brighten.ac.check.WAction;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckData;
import dev.brighten.ac.check.CheckType;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.check.impl.speed.Horizontal;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying;
@@ -38,14 +38,14 @@ public class VelocityB extends Check {
private int ticks;
private static final double[] moveValues = new double[] {-0.98, 0, 0.98};
Action<WPacketPlayInUseEntity> usePacket = packet -> {
WAction<WPacketPlayInUseEntity> usePacket = packet -> {
if(!useEntity
&& packet.getAction().equals(WPacketPlayInUseEntity.EnumEntityUseAction.ATTACK)) {
useEntity = true;
}
};
Action<WPacketPlayInFlying> flying = packet -> {
WAction<WPacketPlayInFlying> flying = packet -> {
check: {
if((pvX != 0 || pvZ != 0) && (player.getMovement().getDeltaX() != 0
|| player.getMovement().getDeltaY() != 0
@@ -1,9 +1,9 @@
package dev.brighten.ac.check.impl.world;
import dev.brighten.ac.check.Action;
import dev.brighten.ac.check.WAction;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckData;
import dev.brighten.ac.check.CheckType;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.packet.ProtocolVersion;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInBlockPlace;
@@ -33,7 +33,7 @@ public class BlockA extends Check {
private final MaxDouble verbose = new MaxDouble(20);
private Queue<Tuple<Block, SimpleCollisionBox>> blockPlacements = new LinkedBlockingQueue<>();
Action<WPacketPlayInBlockPlace> blockPlace = packet -> {
WAction<WPacketPlayInBlockPlace> blockPlace = packet -> {
Location loc = packet.getBlockPos().toBukkitVector().toLocation(player.getBukkitPlayer().getWorld());
Optional<Block> optionalBlock = BlockUtils.getBlockAsync(loc);
@@ -63,7 +63,7 @@ public class BlockA extends Check {
blockPlacements.add(new Tuple<>(block, simpleBox.expand(0.1)));
};
Action<WPacketPlayInFlying> flying = packet -> {
WAction<WPacketPlayInFlying> flying = packet -> {
Tuple<Block, SimpleCollisionBox> tuple;
while((tuple = blockPlacements.poll()) != null) {
@@ -1,9 +1,9 @@
package dev.brighten.ac.check.impl.world;
import dev.brighten.ac.check.Action;
import dev.brighten.ac.check.WAction;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckData;
import dev.brighten.ac.check.CheckType;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.data.APlayer;
import org.bukkit.block.Block;
import org.bukkit.event.block.BlockPlaceEvent;
@@ -14,7 +14,7 @@ public class BlockB extends Check {
super(player);
}
Action<BlockPlaceEvent> blockPlaceEvent = event -> {
WAction<BlockPlaceEvent> blockPlaceEvent = event -> {
Block ba = event.getBlockAgainst();
if (!event.getBlockPlaced().getType().isBlock()) return;
@@ -1,9 +1,9 @@
package dev.brighten.ac.check.impl.world;
import dev.brighten.ac.check.Action;
import dev.brighten.ac.check.WAction;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckData;
import dev.brighten.ac.check.CheckType;
import dev.brighten.ac.api.check.CheckType;
import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInBlockPlace;
import dev.brighten.ac.packet.wrapper.in.WPacketPlayInFlying;
@@ -20,7 +20,7 @@ public class BlockC extends Check {
super(player);
}
Action<WPacketPlayInFlying> flying = packet -> {
WAction<WPacketPlayInFlying> flying = packet -> {
if(player.getInfo().isCreative() || player.getMovement().isExcuseNextFlying()) return;
long timestamp = System.currentTimeMillis();
if(place) {
@@ -34,7 +34,7 @@ public class BlockC extends Check {
}
};
Action<WPacketPlayInBlockPlace> blockPlace = packet -> {
WAction<WPacketPlayInBlockPlace> blockPlace = packet -> {
if(player.pastLocations.isEmpty()) return;
KLocation lastMovePacket = player.pastLocations.getLast().one;
@@ -15,8 +15,10 @@ import io.netty.buffer.Unpooled;
import lombok.val;
import net.minecraft.server.v1_8_R3.PacketDataSerializer;
import net.minecraft.server.v1_8_R3.PacketPlayOutCustomPayload;
import net.minecraft.server.v1_8_R3.PacketPlayOutTitle;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.craftbukkit.v1_8_R3.util.CraftChatMessage;
import org.bukkit.entity.Player;
import java.io.UnsupportedEncodingException;
@@ -86,6 +88,7 @@ public class AnticheatCommand extends BaseCommand {
}
@Subcommand("alerts")
@HelpCommand
@CommandPermission("anticheat.command.alerts")
@Description("Toggle anticheat alerts")
public void onAlerts(Player pl) {
@@ -105,6 +108,14 @@ public class AnticheatCommand extends BaseCommand {
}
}
@Subcommand("title")
@Private
public void onTitle(CommandSender sender, OnlinePlayer target, String title) {
PacketPlayOutTitle packetSubtitle = new PacketPlayOutTitle(PacketPlayOutTitle.EnumTitleAction.TITLE, CraftChatMessage.fromString(Color.translate(title))[0]);
HandlerAbstract.getHandler().sendPacket(target.getPlayer(), packetSubtitle);
sender.sendMessage(Color.Green + "Sent title!");
}
@Subcommand("playerinfo|info|pi")
@Description("Get player's information")
@Syntax("[player]")
+54 -46
View File
@@ -1,10 +1,7 @@
package dev.brighten.ac.data;
import dev.brighten.ac.Anticheat;
import dev.brighten.ac.check.Action;
import dev.brighten.ac.check.Check;
import dev.brighten.ac.check.CheckStatic;
import dev.brighten.ac.check.TimedAction;
import dev.brighten.ac.check.*;
import dev.brighten.ac.data.handlers.BlockInformation;
import dev.brighten.ac.data.handlers.GeneralInformation;
import dev.brighten.ac.data.handlers.LagInformation;
@@ -85,8 +82,8 @@ public class APlayer {
private final List<Consumer<Vector>> onVelocityTasks = new ArrayList<>();
public final EvictingList<Tuple<KLocation, Double>> pastLocations = new EvictingList<>(20);
private final Map<Class<?>, Action<?>[]> events = new HashMap<>();
private final Map<Class<?>, TimedAction<?>[]> eventsWithTimestamp = new HashMap<>();
private final Map<Class<?>, WAction<?>[]> events = new HashMap<>();
private final Map<Class<?>, TimedWAction<?>[]> eventsWithTimestamp = new HashMap<>();
@Setter
@Getter
@@ -127,8 +124,51 @@ public class APlayer {
this.blockInfo = new BlockInformation(this);
// Grabbing the protocol version of the player.
Anticheat.INSTANCE.getScheduler().execute(() ->
playerVersion = ProtocolVersion.getVersion(ProtocolAPI.INSTANCE.getPlayerVersion(getBukkitPlayer())));
Anticheat.INSTANCE.getScheduler().execute(() -> {
playerVersion = ProtocolVersion.getVersion(ProtocolAPI.INSTANCE.getPlayerVersion(getBukkitPlayer()));
// Enabling checks for players on join
for (CheckStatic checkClass : Anticheat.INSTANCE.getCheckManager().getCheckClasses()) {
CheckData data = checkClass.getCheckClass().getAnnotation(CheckData.class);
//Version checks
if(playerVersion.isAbove(data.maxVersion()) || playerVersion.isBelow(data.minVersion())) {
Anticheat.INSTANCE.alog("Player " + getBukkitPlayer().getName() +
" is not on the right version for check " + data.name()
+ " (version: " + playerVersion.name() + ")");
continue;
}
Check check = checkClass.playerInit(this);
for (Tuple<WrappedField, Class<?>> tuple : checkClass.getActions()) {
WAction<?> action = tuple.one.get(check);
events.compute(tuple.two, (packetClass, array) -> {
if (array == null) {
return new WAction<?>[]{action};
} else {
WAction<?>[] newArray = Arrays.copyOf(array, array.length + 1);
newArray[array.length] = action;
return newArray;
}
});
}
for (Tuple<WrappedField, Class<?>> tuple : checkClass.getTimedActions()) {
TimedWAction<?> action = tuple.one.get(check);
eventsWithTimestamp.compute(tuple.two, (packetClass, array) -> {
if (array == null) {
return new TimedWAction<?>[]{action};
} else {
TimedWAction<?>[] newArray = Arrays.copyOf(array, array.length + 1);
newArray[array.length] = action;
return newArray;
}
});
}
}
});
// Enabling alerts for players on join if they have the permissions to
if(getBukkitPlayer().hasPermission("anticheat.command.alerts")
@@ -136,38 +176,6 @@ public class APlayer {
Check.alertsEnabled.add(getUuid());
getBukkitPlayer().spigot().sendMessage(Messages.ALERTS_ON);
}
// Enabling checks for players on join
for (CheckStatic checkClass : Anticheat.INSTANCE.getCheckManager().getCheckClasses()) {
Check check = checkClass.playerInit(this);
for (Tuple<WrappedField, Class<?>> tuple : checkClass.getActions()) {
Action<?> action = tuple.one.get(check);
events.compute(tuple.two, (packetClass, array) -> {
if (array == null) {
return new Action<?>[]{action};
} else {
Action<?>[] newArray = Arrays.copyOf(array, array.length + 1);
newArray[array.length] = action;
return newArray;
}
});
}
for (Tuple<WrappedField, Class<?>> tuple : checkClass.getTimedActions()) {
TimedAction<?> action = tuple.one.get(check);
eventsWithTimestamp.compute(tuple.two, (packetClass, array) -> {
if (array == null) {
return new TimedAction<?>[]{action};
} else {
TimedAction<?>[] newArray = Arrays.copyOf(array, array.length + 1);
newArray[array.length] = action;
return newArray;
}
});
}
}
}
protected void unload() {
@@ -179,8 +187,8 @@ public class APlayer {
public void callEvent(Event event) {
if(events.containsKey(event.getClass())) {
Action<Event>[] actions = (Action<Event>[]) events.get(event.getClass());
for (Action<Event> action : actions) {
WAction<Event>[] actions = (WAction<Event>[]) events.get(event.getClass());
for (WAction<Event> action : actions) {
action.invoke(event);
}
}
@@ -189,14 +197,14 @@ public class APlayer {
//TODO When using WPacket wrappers only, make this strictly WPacket param based only
public void callPacket(Object packet, long timestamp) {
if(events.containsKey(packet.getClass())) {
Action<Object>[] actions = (Action<Object>[]) events.get(packet.getClass());
for (Action<Object> action : actions) {
WAction<Object>[] actions = (WAction<Object>[]) events.get(packet.getClass());
for (WAction<Object> action : actions) {
action.invoke(packet);
}
}
if(eventsWithTimestamp.containsKey(packet.getClass())) {
TimedAction<Object>[] actions = (TimedAction<Object>[]) eventsWithTimestamp.get(packet.getClass());
for (TimedAction<Object> action : actions) {
TimedWAction<Object>[] actions = (TimedWAction<Object>[]) eventsWithTimestamp.get(packet.getClass());
for (TimedWAction<Object> action : actions) {
action.invoke(packet, timestamp);
}
}
@@ -26,10 +26,10 @@ public class GeneralInformation {
lastSneak = new TickTimer(), velocity = new TickTimer(), lastCancel = new TickTimer(),
slimeTimer = new TickTimer(), lastElytra = new TickTimer(), blockAbove = new TickTimer(),
lastPlace = new TickTimer(), climbTimer = new TickTimer(), lastUseItem = new TickTimer(),
lastLiquid = new TickTimer();
lastLiquid = new TickTimer(), lastBlockDig = new TickTimer(), lastBlockPlace = new TickTimer();
public LivingEntity target;
public boolean serverGround, lastServerGround, canFly, nearGround, worldLoaded, generalCancel, inVehicle, creative,
sneaking, lsneaking, sprinting, gliding, riptiding, wasOnSlime, onLadder, doingVelocity;
sneaking, lsneaking, sprinting, gliding, riptiding, wasOnSlime, onLadder, doingVelocity, breakingBlock;
public List<Entity> nearbyEntities = Collections.emptyList();
public PastLocation targetPastLocation = new PastLocation();
public KLocation lastKnownGoodPosition;
@@ -275,6 +275,8 @@ public class PacketHandler {
IntVector pos = packet.getBlockPos();
ItemStack stack = packet.getItemStack();
player.getInfo().getLastBlockPlace().reset();
// Used item
if(pos.getX() == -1 && (pos.getY() == 255 | pos.getY() == -1) && pos.getZ() == -1
&& stack != null
@@ -288,6 +290,7 @@ public class PacketHandler {
case BLOCK_DIG: {
WPacketPlayInBlockDig packet = (WPacketPlayInBlockDig) packetObject;
player.getInfo().getLastBlockDig().reset();
player.getBlockUpdateHandler().onDig(packet);
break;
}
@@ -1,5 +1,6 @@
package dev.brighten.ac.handler.protocolsupport;
import dev.brighten.ac.Anticheat;
import dev.brighten.ac.handler.protocolsupport.impl.NoAPI;
import dev.brighten.ac.handler.protocolsupport.impl.ProtocolSupport;
import dev.brighten.ac.handler.protocolsupport.impl.ViaVersionAPI;
@@ -21,9 +22,14 @@ public class ProtocolAPI {
public ProtocolAPI() {
if(Bukkit.getPluginManager().isPluginEnabled("ViaVersion")) {
Anticheat.INSTANCE.alog("Using ViaVersion for ProtocolAPI");
INSTANCE = new ViaVersionAPI();
} else if(Bukkit.getPluginManager().isPluginEnabled("ProtocolSupport")) {
Anticheat.INSTANCE.alog("Using ProtocolSupport for ProtocolAPI");
INSTANCE = new ProtocolSupport();
} else INSTANCE = new NoAPI();
} else {
Anticheat.INSTANCE.alog("Using Vanilla API for ProtocolAPI");
INSTANCE = new NoAPI();
}
}
}
@@ -5,15 +5,18 @@ import dev.brighten.ac.data.APlayer;
import dev.brighten.ac.utils.Init;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
@Init
public class GeneralListener implements Listener {
@EventHandler
@EventHandler(priority = EventPriority.HIGH)
public void onDamage(EntityDamageByEntityEvent event) {
if(event.getDamager() instanceof Player) {
APlayer player = Anticheat.INSTANCE.getPlayerRegistry().getPlayer(event.getDamager().getUniqueId()).
@@ -28,17 +31,25 @@ public class GeneralListener implements Listener {
}
}
@EventHandler
@EventHandler(priority = EventPriority.MONITOR)
public void onInteract(PlayerInteractEvent event) {
Anticheat.INSTANCE.getPlayerRegistry().getPlayer(event.getPlayer().getUniqueId()).ifPresent(player -> {
player.getInfo().breakingBlock = event.getAction().equals(Action.LEFT_CLICK_BLOCK);
});
}
@EventHandler(priority = EventPriority.MONITOR)
public void onTeleport(PlayerTeleportEvent event) {
if(event.getFrom().getWorld().equals(event.getTo().getWorld())) return;
if(event.getFrom().getWorld().equals(event.getTo().getWorld()) || event.isCancelled()) return;
Anticheat.INSTANCE.getPlayerRegistry().getPlayer(event.getPlayer().getUniqueId())
.ifPresent(player -> player.getBlockUpdateHandler().onWorldChange());
}
@EventHandler
@EventHandler(priority = EventPriority.MONITOR)
public void onPlace(BlockPlaceEvent event) {
Anticheat.INSTANCE.getPlayerRegistry().getPlayer(event.getPlayer().getUniqueId())
.ifPresent(player -> player.callEvent(event));
if(!event.isCancelled())
Anticheat.INSTANCE.getPlayerRegistry().getPlayer(event.getPlayer().getUniqueId())
.ifPresent(player -> player.callEvent(event));
}
}
@@ -54,6 +54,8 @@ public enum ProtocolVersion {
V1_18_2(758, "v1_18_R2"),
V1_19(759, "v1_19_R1"),
v1_19_1(760, "v1_19_R1"),
UNKNOWN(-1, "UNKNOWN");
@Getter
@@ -31,7 +31,6 @@ public abstract class HandlerAbstract{
public static void shutdown() {
Bukkit.getOnlinePlayers().forEach(handler::remove);
handler = null;
}
public abstract void add(Player player);
View File
+2 -1
View File
@@ -1,4 +1,5 @@
name: Anticheat
main: dev.brighten.ac.Anticheat
version: 1.0
author: funkemunky
author: funkemunky
softdepend: [ViaVersion]