diff --git a/API/pom.xml b/API/pom.xml
new file mode 100644
index 0000000..2d1a4d7
--- /dev/null
+++ b/API/pom.xml
@@ -0,0 +1,62 @@
+
+
+
+ 4.0.0
+
+ dev.brighten.ac
+ API
+ 1.0
+
+
+ UTF-8
+
+
+
+
+
+ funkemunky-releases
+ https://nexus.funkemunky.cc/content/repositories/releases/
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+ 8
+ 8
+ -XDignore.symbol.file
+ false
+
+
+ org.projectlombok
+ lombok
+ 1.18.20
+
+
+
+
+
+
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.24
+ provided
+
+
+ org.github.spigot
+ 1.8.8
+ 1.8.8
+ provided
+
+
+
+
\ No newline at end of file
diff --git a/API/src/main/java/dev/brighten/ac/api/AnticheatAPI.java b/API/src/main/java/dev/brighten/ac/api/AnticheatAPI.java
new file mode 100644
index 0000000..cdceced
--- /dev/null
+++ b/API/src/main/java/dev/brighten/ac/api/AnticheatAPI.java
@@ -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> 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 getAllEvents() {
+ final List allEvents = new ArrayList<>();
+
+ synchronized (registeredEvents) {
+ for (List events : registeredEvents.values()) {
+ allEvents.addAll(events);
+ }
+ }
+
+ allEvents.sort(Comparator.comparing(e -> e.priority().getSlot()));
+
+ return allEvents;
+ }
+
+}
diff --git a/src/main/java/dev/brighten/ac/check/CheckType.java b/API/src/main/java/dev/brighten/ac/api/check/CheckType.java
similarity index 62%
rename from src/main/java/dev/brighten/ac/check/CheckType.java
rename to API/src/main/java/dev/brighten/ac/api/check/CheckType.java
index 5d7bfb8..d191498 100644
--- a/src/main/java/dev/brighten/ac/check/CheckType.java
+++ b/API/src/main/java/dev/brighten/ac/api/check/CheckType.java
@@ -1,7 +1,8 @@
-package dev.brighten.ac.check;
+package dev.brighten.ac.api.check;
public enum CheckType {
COMBAT,
+ AUTOCLICKER,
MOVEMENT,
BLOCK,
INTERACT,
diff --git a/API/src/main/java/dev/brighten/ac/api/check/ECheck.java b/API/src/main/java/dev/brighten/ac/api/check/ECheck.java
new file mode 100644
index 0000000..d362fd3
--- /dev/null
+++ b/API/src/main/java/dev/brighten/ac/api/check/ECheck.java
@@ -0,0 +1,9 @@
+package dev.brighten.ac.api.check;
+
+public interface ECheck {
+ String getName();
+
+ float getVl();
+
+ CheckType getCheckType();
+}
diff --git a/API/src/main/java/dev/brighten/ac/api/event/AnticheatEvent.java b/API/src/main/java/dev/brighten/ac/api/event/AnticheatEvent.java
new file mode 100644
index 0000000..d55fb6a
--- /dev/null
+++ b/API/src/main/java/dev/brighten/ac/api/event/AnticheatEvent.java
@@ -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 commands, boolean cancelled);
+
+ FlagResult onFlag(Player player, ECheck check, String information, boolean cancelled);
+
+ CancelResult onCancel(Player player, ECheck check, boolean cancelled);
+
+ EventPriority priority();
+
+
+}
diff --git a/API/src/main/java/dev/brighten/ac/api/event/result/CancelResult.java b/API/src/main/java/dev/brighten/ac/api/event/result/CancelResult.java
new file mode 100644
index 0000000..70b551c
--- /dev/null
+++ b/API/src/main/java/dev/brighten/ac/api/event/result/CancelResult.java
@@ -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;
+}
diff --git a/API/src/main/java/dev/brighten/ac/api/event/result/FlagResult.java b/API/src/main/java/dev/brighten/ac/api/event/result/FlagResult.java
new file mode 100644
index 0000000..9918230
--- /dev/null
+++ b/API/src/main/java/dev/brighten/ac/api/event/result/FlagResult.java
@@ -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;
+}
diff --git a/API/src/main/java/dev/brighten/ac/api/event/result/PunishResult.java b/API/src/main/java/dev/brighten/ac/api/event/result/PunishResult.java
new file mode 100644
index 0000000..46a47b6
--- /dev/null
+++ b/API/src/main/java/dev/brighten/ac/api/event/result/PunishResult.java
@@ -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 commands;
+}
diff --git a/pom.xml b/pom.xml
index cd8e339..40c2d7c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -105,6 +105,12 @@
1.8.8
provided
+
+ dev.brighten.ac
+ API
+ 1.0
+ compile
+
org.github.spigot
1.7.10
diff --git a/src/main/java/dev/brighten/ac/Anticheat.java b/src/main/java/dev/brighten/ac/Anticheat.java
index c7582ab..da357ad 100644
--- a/src/main/java/dev/brighten/ac/Anticheat.java
+++ b/src/main/java/dev/brighten/ac/Anticheat.java
@@ -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,
diff --git a/src/main/java/dev/brighten/ac/check/Check.java b/src/main/java/dev/brighten/ac/check/Check.java
index d377cc9..7cce012 100644
--- a/src/main/java/dev/brighten/ac/check/Check.java
+++ b/src/main/java/dev/brighten/ac/check/Check.java
@@ -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 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, "");
}
diff --git a/src/main/java/dev/brighten/ac/check/CheckConfig.java b/src/main/java/dev/brighten/ac/check/CheckConfig.java
new file mode 100644
index 0000000..23a4789
--- /dev/null
+++ b/src/main/java/dev/brighten/ac/check/CheckConfig.java
@@ -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 punishmentCommands = Arrays.asList("kick %player% Unfair Advantage (%check%)");
+}
diff --git a/src/main/java/dev/brighten/ac/check/CheckData.java b/src/main/java/dev/brighten/ac/check/CheckData.java
index ffaca6d..3ffff1c 100644
--- a/src/main/java/dev/brighten/ac/check/CheckData.java
+++ b/src/main/java/dev/brighten/ac/check/CheckData.java
@@ -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;
}
diff --git a/src/main/java/dev/brighten/ac/check/CheckStatic.java b/src/main/java/dev/brighten/ac/check/CheckStatic.java
index 29b3b08..95fd6bb 100644
--- a/src/main/java/dev/brighten/ac/check/CheckStatic.java
+++ b/src/main/java/dev/brighten/ac/check/CheckStatic.java
@@ -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));
diff --git a/src/main/java/dev/brighten/ac/check/TimedAction.java b/src/main/java/dev/brighten/ac/check/TimedWAction.java
similarity index 73%
rename from src/main/java/dev/brighten/ac/check/TimedAction.java
rename to src/main/java/dev/brighten/ac/check/TimedWAction.java
index 4a53c89..8e2f335 100644
--- a/src/main/java/dev/brighten/ac/check/TimedAction.java
+++ b/src/main/java/dev/brighten/ac/check/TimedWAction.java
@@ -1,6 +1,6 @@
package dev.brighten.ac.check;
@FunctionalInterface
-public interface TimedAction {
+public interface TimedWAction {
void invoke(T event, long timestamp);
}
diff --git a/src/main/java/dev/brighten/ac/check/Action.java b/src/main/java/dev/brighten/ac/check/WAction.java
similarity index 72%
rename from src/main/java/dev/brighten/ac/check/Action.java
rename to src/main/java/dev/brighten/ac/check/WAction.java
index 8f09317..f58f92d 100644
--- a/src/main/java/dev/brighten/ac/check/Action.java
+++ b/src/main/java/dev/brighten/ac/check/WAction.java
@@ -1,6 +1,6 @@
package dev.brighten.ac.check;
@FunctionalInterface
-public interface Action {
+public interface WAction {
void invoke(T event);
}
diff --git a/src/main/java/dev/brighten/ac/check/impl/combat/Aim.java b/src/main/java/dev/brighten/ac/check/impl/combat/Aim.java
index f433937..0a76805 100644
--- a/src/main/java/dev/brighten/ac/check/impl/combat/Aim.java
+++ b/src/main/java/dev/brighten/ac/check/impl/combat/Aim.java
@@ -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 onFlying = (packet) -> {
+ WAction onFlying = (packet) -> {
if(!packet.isLooked()) return;
if(player.getMovement().getYawGcdList().size() < 40) {
diff --git a/src/main/java/dev/brighten/ac/check/impl/combat/Hitbox.java b/src/main/java/dev/brighten/ac/check/impl/combat/Hitbox.java
index ad0a0e4..2ed5424 100644
--- a/src/main/java/dev/brighten/ac/check/impl/combat/Hitbox.java
+++ b/src/main/java/dev/brighten/ac/check/impl/combat/Hitbox.java
@@ -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 useEntity = packet -> {
+ WAction 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 onFlying = packet -> {
+ WAction onFlying = packet -> {
if(player.getInfo().isCreative() || player.getInfo().isInVehicle()) {
attacks.clear();
return;
diff --git a/src/main/java/dev/brighten/ac/check/impl/combat/autoclicker/AutoclickerA.java b/src/main/java/dev/brighten/ac/check/impl/combat/autoclicker/AutoclickerA.java
new file mode 100644
index 0000000..4ce8370
--- /dev/null
+++ b/src/main/java/dev/brighten/ac/check/impl/combat/autoclicker/AutoclickerA.java
@@ -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 flying = (packet) -> {
+ flyingTicks++;
+ if(flyingTicks >= 20) {
+ if(cps > 22) {
+ if(cps > 30) {
+ punish();
+ }
+ flag("cps=%s", cps);
+ }
+ cps = 0;
+ }
+ };
+
+ WAction armAnimation = packet -> {
+ if(!player.getInfo().breakingBlock
+ && player.getInfo().getLastBlockDig().isPassed(1)
+ && player.getInfo().getLastBlockPlace().isPassed(1)) {
+ cps++;
+ }
+ debug("breaking=%s", player.getInfo().breakingBlock);
+ };
+}
diff --git a/src/main/java/dev/brighten/ac/check/impl/combat/autoclicker/AutoclickerB.java b/src/main/java/dev/brighten/ac/check/impl/combat/autoclicker/AutoclickerB.java
new file mode 100644
index 0000000..c2ff20e
--- /dev/null
+++ b/src/main/java/dev/brighten/ac/check/impl/combat/autoclicker/AutoclickerB.java
@@ -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 flyingPacket = (packet, timestamp) -> {
+ if(player.getMovement().getLastTeleport().isPassed(1))
+ lastFlying = timestamp;
+ };
+
+ TimedWAction 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);
+ };
+}
diff --git a/src/main/java/dev/brighten/ac/check/impl/fly/FlyA.java b/src/main/java/dev/brighten/ac/check/impl/fly/FlyA.java
index 959ee31..fab5c2a 100644
--- a/src/main/java/dev/brighten/ac/check/impl/fly/FlyA.java
+++ b/src/main/java/dev/brighten/ac/check/impl/fly/FlyA.java
@@ -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 flying = packet -> {
+ WAction flying = packet -> {
if(!packet.isMoved() || (player.getMovement().getDeltaXZ() == 0
&& player.getMovement().getDeltaY() == 0)) {
return;
diff --git a/src/main/java/dev/brighten/ac/check/impl/fly/FlyB.java b/src/main/java/dev/brighten/ac/check/impl/fly/FlyB.java
index 62a416d..d321297 100644
--- a/src/main/java/dev/brighten/ac/check/impl/fly/FlyB.java
+++ b/src/main/java/dev/brighten/ac/check/impl/fly/FlyB.java
@@ -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 flying = packet -> {
+ WAction flying = packet -> {
if(player.getInfo().isNearGround()) lastNearGround.reset();
if(!packet.isMoved() || player.getInfo().isGeneralCancel()) return;
diff --git a/src/main/java/dev/brighten/ac/check/impl/nofall/NoFallA.java b/src/main/java/dev/brighten/ac/check/impl/nofall/NoFallA.java
index db9bd23..9986bd6 100644
--- a/src/main/java/dev/brighten/ac/check/impl/nofall/NoFallA.java
+++ b/src/main/java/dev/brighten/ac/check/impl/nofall/NoFallA.java
@@ -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 flying = packet -> {
+ WAction flying = packet -> {
if(player.getInfo().isGeneralCancel()
|| (player.getMovement().getDeltaXZ() == 0 && player.getMovement().getDeltaY() == 0)
|| player.getBlockInfo().inLiquid
diff --git a/src/main/java/dev/brighten/ac/check/impl/nofall/NoFallB.java b/src/main/java/dev/brighten/ac/check/impl/nofall/NoFallB.java
index 3d194d6..0eed846 100644
--- a/src/main/java/dev/brighten/ac/check/impl/nofall/NoFallB.java
+++ b/src/main/java/dev/brighten/ac/check/impl/nofall/NoFallB.java
@@ -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 flying = packet -> {
+ WAction flying = packet -> {
if(player.getMovement().getLastTeleport().isNotPassed(3)
|| player.getMovement().getMoveTicks() < 2
|| player.getInfo().canFly
diff --git a/src/main/java/dev/brighten/ac/check/impl/order/Place.java b/src/main/java/dev/brighten/ac/check/impl/order/Place.java
new file mode 100644
index 0000000..c9b8b64
--- /dev/null
+++ b/src/main/java/dev/brighten/ac/check/impl/order/Place.java
@@ -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 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 flying = (packet, timestamp) -> {
+ if(player.getMovement().getLastTeleport().isPassed(1))
+ lastFlying = timestamp;
+ };
+}
diff --git a/src/main/java/dev/brighten/ac/check/impl/order/UseEntity.java b/src/main/java/dev/brighten/ac/check/impl/order/UseEntity.java
new file mode 100644
index 0000000..f8d894e
--- /dev/null
+++ b/src/main/java/dev/brighten/ac/check/impl/order/UseEntity.java
@@ -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 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 flying = (packet, timestamp) -> {
+ if(player.getMovement().getLastTeleport().isPassed(0))
+ lastFlying = timestamp;
+ };
+}
diff --git a/src/main/java/dev/brighten/ac/check/impl/speed/Horizontal.java b/src/main/java/dev/brighten/ac/check/impl/speed/Horizontal.java
index a7084ac..d4192c3 100644
--- a/src/main/java/dev/brighten/ac/check/impl/speed/Horizontal.java
+++ b/src/main/java/dev/brighten/ac/check/impl/speed/Horizontal.java
@@ -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 flying = packet -> {
+ WAction flying = packet -> {
Block underBlock = BlockUtils.getBlock(player.getMovement().getTo().getLoc()
.toLocation(player.getBukkitPlayer().getWorld())
.subtract(0, 1, 0)),
diff --git a/src/main/java/dev/brighten/ac/check/impl/velocity/VelocityA.java b/src/main/java/dev/brighten/ac/check/impl/velocity/VelocityA.java
index d8b7910..59da101 100644
--- a/src/main/java/dev/brighten/ac/check/impl/velocity/VelocityA.java
+++ b/src/main/java/dev/brighten/ac/check/impl/velocity/VelocityA.java
@@ -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 flying = packet -> {
+ WAction flying = packet -> {
if(currentVelocity != null && currentVelocity.getY() > 0
&& !player.getBlockInfo().inWeb
&& !player.getBlockInfo().onClimbable
diff --git a/src/main/java/dev/brighten/ac/check/impl/velocity/VelocityB.java b/src/main/java/dev/brighten/ac/check/impl/velocity/VelocityB.java
index 3c99a26..27b7193 100644
--- a/src/main/java/dev/brighten/ac/check/impl/velocity/VelocityB.java
+++ b/src/main/java/dev/brighten/ac/check/impl/velocity/VelocityB.java
@@ -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 usePacket = packet -> {
+ WAction usePacket = packet -> {
if(!useEntity
&& packet.getAction().equals(WPacketPlayInUseEntity.EnumEntityUseAction.ATTACK)) {
useEntity = true;
}
};
- Action flying = packet -> {
+ WAction flying = packet -> {
check: {
if((pvX != 0 || pvZ != 0) && (player.getMovement().getDeltaX() != 0
|| player.getMovement().getDeltaY() != 0
diff --git a/src/main/java/dev/brighten/ac/check/impl/world/BlockA.java b/src/main/java/dev/brighten/ac/check/impl/world/BlockA.java
index 8eeda06..0b61aa1 100644
--- a/src/main/java/dev/brighten/ac/check/impl/world/BlockA.java
+++ b/src/main/java/dev/brighten/ac/check/impl/world/BlockA.java
@@ -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> blockPlacements = new LinkedBlockingQueue<>();
- Action blockPlace = packet -> {
+ WAction blockPlace = packet -> {
Location loc = packet.getBlockPos().toBukkitVector().toLocation(player.getBukkitPlayer().getWorld());
Optional optionalBlock = BlockUtils.getBlockAsync(loc);
@@ -63,7 +63,7 @@ public class BlockA extends Check {
blockPlacements.add(new Tuple<>(block, simpleBox.expand(0.1)));
};
- Action flying = packet -> {
+ WAction flying = packet -> {
Tuple tuple;
while((tuple = blockPlacements.poll()) != null) {
diff --git a/src/main/java/dev/brighten/ac/check/impl/world/BlockB.java b/src/main/java/dev/brighten/ac/check/impl/world/BlockB.java
index dc1c97e..41cb2e0 100644
--- a/src/main/java/dev/brighten/ac/check/impl/world/BlockB.java
+++ b/src/main/java/dev/brighten/ac/check/impl/world/BlockB.java
@@ -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 = event -> {
+ WAction blockPlaceEvent = event -> {
Block ba = event.getBlockAgainst();
if (!event.getBlockPlaced().getType().isBlock()) return;
diff --git a/src/main/java/dev/brighten/ac/check/impl/world/BlockC.java b/src/main/java/dev/brighten/ac/check/impl/world/BlockC.java
index 8de63e3..7698146 100644
--- a/src/main/java/dev/brighten/ac/check/impl/world/BlockC.java
+++ b/src/main/java/dev/brighten/ac/check/impl/world/BlockC.java
@@ -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 flying = packet -> {
+ WAction 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 blockPlace = packet -> {
+ WAction blockPlace = packet -> {
if(player.pastLocations.isEmpty()) return;
KLocation lastMovePacket = player.pastLocations.getLast().one;
diff --git a/src/main/java/dev/brighten/ac/command/AnticheatCommand.java b/src/main/java/dev/brighten/ac/command/AnticheatCommand.java
index b4b1be9..cb17fff 100644
--- a/src/main/java/dev/brighten/ac/command/AnticheatCommand.java
+++ b/src/main/java/dev/brighten/ac/command/AnticheatCommand.java
@@ -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]")
diff --git a/src/main/java/dev/brighten/ac/data/APlayer.java b/src/main/java/dev/brighten/ac/data/APlayer.java
index ea6e6a8..37821f3 100644
--- a/src/main/java/dev/brighten/ac/data/APlayer.java
+++ b/src/main/java/dev/brighten/ac/data/APlayer.java
@@ -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> onVelocityTasks = new ArrayList<>();
public final EvictingList> pastLocations = new EvictingList<>(20);
- private final Map, Action>[]> events = new HashMap<>();
- private final Map, TimedAction>[]> eventsWithTimestamp = new HashMap<>();
+ private final Map, WAction>[]> events = new HashMap<>();
+ private final Map, 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> 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> 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> 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> 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[] actions = (Action[]) events.get(event.getClass());
- for (Action action : actions) {
+ WAction[] actions = (WAction[]) events.get(event.getClass());
+ for (WAction 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