Anticheat Logging #299

Remove MAC
Add AntiHack Logging
Change thresholds, add notifs, move stuff around
Add warning if check does not exist
Handle multiple bans when ranked TWITCH+
Prevent punishment abuse
This commit is contained in:
cnr 2016-12-01 01:24:05 -06:00
parent df741fd394
commit cae9d2f67e
49 changed files with 2091 additions and 1744 deletions

View File

@ -20,6 +20,11 @@
<groupId>org.apache.httpcomponents</groupId> <groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId> <artifactId>httpclient</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.mineplex</groupId>
<artifactId>mineplex-serverdata</artifactId>
<version>dev-SNAPSHOT</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -4,6 +4,7 @@ import com.google.common.collect.Sets;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerQuitEvent;
@ -218,7 +219,7 @@ public class PlayerMap<V> implements Map<UUID, V>
private static class RemovalListener implements Listener private static class RemovalListener implements Listener
{ {
@EventHandler @EventHandler (priority = EventPriority.MONITOR)
public void onQuit(PlayerQuitEvent event) public void onQuit(PlayerQuitEvent event)
{ {
synchronized (LOCK) synchronized (LOCK)

View File

@ -1,7 +1,10 @@
package mineplex.core.common.util; package mineplex.core.common.util;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import mineplex.core.common.events.PlayerRecieveBroadcastEvent; import mineplex.core.common.events.PlayerRecieveBroadcastEvent;
import mineplex.serverdata.Region;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.Sound; import org.bukkit.Sound;
@ -13,6 +16,7 @@ import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.*; import java.util.*;
@ -91,7 +95,7 @@ public class UtilServer
public static double getFilledPercent() public static double getFilledPercent()
{ {
return (double)getPlayers().length / (double)UtilServer.getServer().getMaxPlayers(); return (double) getPlayers().length / (double) UtilServer.getServer().getMaxPlayers();
} }
public static void RegisterEvents(Listener listener) public static void RegisterEvents(Listener listener)
@ -135,6 +139,16 @@ public class UtilServer
return getPlugin().getConfig().getString("serverstatus.name"); return getPlugin().getConfig().getString("serverstatus.name");
} }
public static Region getRegion()
{
return getPlugin().getConfig().getBoolean("serverstatus.us") ? Region.US : Region.EU;
}
public static String getGroup()
{
return getPlugin().getConfig().getString("serverstatus.group");
}
public static boolean isTestServer() public static boolean isTestServer()
{ {
return getPlugin().getConfig().getString("serverstatus.group").equalsIgnoreCase("Testing"); return getPlugin().getConfig().getString("serverstatus.group").equalsIgnoreCase("Testing");
@ -180,4 +194,39 @@ public class UtilServer
throwable.printStackTrace(System.out); throwable.printStackTrace(System.out);
} }
} }
public static BukkitTask runAsync(Runnable runnable)
{
return getPlugin().getServer().getScheduler().runTaskAsynchronously(getPlugin(), runnable);
}
public static BukkitTask runAsync(Runnable runnable, long time)
{
return getPlugin().getServer().getScheduler().runTaskLaterAsynchronously(getPlugin(), runnable, time);
}
public static BukkitTask runAsyncTimer(Runnable runnable, long time, long period)
{
return getPlugin().getServer().getScheduler().runTaskTimerAsynchronously(getPlugin(), runnable, time, period);
}
public static BukkitTask runSync(Runnable runnable)
{
return getPlugin().getServer().getScheduler().runTask(getPlugin(), runnable);
}
public static BukkitTask runSyncLater(Runnable runnable, long delay)
{
return getPlugin().getServer().getScheduler().runTaskLater(getPlugin(), runnable, delay);
}
public static BukkitTask runSyncTimer(Runnable runnable, long delay, long period)
{
return getPlugin().getServer().getScheduler().runTaskTimer(getPlugin(), runnable, delay, period);
}
public static BukkitTask runSyncTimer(BukkitRunnable runnable, long delay, long period)
{
return runnable.runTaskTimer(getPlugin(), delay, period);
}
} }

View File

@ -45,6 +45,11 @@
<artifactId>anticheat</artifactId> <artifactId>anticheat</artifactId>
<version>1.2</version> <version>1.2</version>
</dependency> </dependency>
<dependency>
<groupId>org.tukaani</groupId>
<artifactId>xz</artifactId>
<version>1.5</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

File diff suppressed because it is too large Load Diff

View File

@ -1,71 +0,0 @@
package mineplex.core.antihack;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import mineplex.serverdata.database.DBPool;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
import org.bukkit.entity.Player;
public class AntiHackRepository
{
private String _serverName;
//private static String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS AntiHack_Kick_Log (id INT NOT NULL AUTO_INCREMENT, updated LONG, playerName VARCHAR(256), motd VARCHAR(56), gameType VARCHAR(56), map VARCHAR(256), serverName VARCHAR(256), report VARCHAR(256), ping VARCHAR(25), PRIMARY KEY (id));";
private static String UPDATE_PLAYER_OFFENSES = "INSERT INTO AntiHack_Kick_Log (updated, playerName, motd, gameType, map, serverName, report, ping) VALUES (now(), ?, ?, ?, ?, ?, ?, ?);";
public AntiHackRepository(String serverName)
{
_serverName = serverName;
}
public void initialize()
{
}
public void saveOffense(final Player player, final String motd, final String game, final String map, final String report)
{
new Thread(new Runnable()
{
public void run()
{
PreparedStatement preparedStatement = null;
try (Connection connection = DBPool.getMineplexStats().getConnection())
{
preparedStatement = connection.prepareStatement(UPDATE_PLAYER_OFFENSES);
preparedStatement.setString(1, player.getName());
preparedStatement.setString(2, motd);
preparedStatement.setString(3, game);
preparedStatement.setString(4, map);
preparedStatement.setString(5, _serverName);
preparedStatement.setString(6, report);
preparedStatement.setString(7, ((CraftPlayer)player).getHandle().ping + "ms");
preparedStatement.execute();
}
catch (Exception exception)
{
exception.printStackTrace();
}
finally
{
if (preparedStatement != null)
{
try
{
preparedStatement.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
}
}
}).start();
}
}

View File

@ -1,5 +1,7 @@
package mineplex.core.antihack; package mineplex.core.antihack;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.minecraft.server.v1_8_R3.ChatComponentText; import net.minecraft.server.v1_8_R3.ChatComponentText;
import net.minecraft.server.v1_8_R3.ChatModifier; import net.minecraft.server.v1_8_R3.ChatModifier;
import net.minecraft.server.v1_8_R3.EnumChatFormat; import net.minecraft.server.v1_8_R3.EnumChatFormat;
@ -25,10 +27,9 @@ public class CheckThresholds
return _friendlyName; return _friendlyName;
} }
public IChatBaseComponent format(int violationLevel) public void format(ComponentBuilder builder, int violationLevel)
{ {
EnumChatFormat color = getSeverity(violationLevel)._color; builder.append(_friendlyName, ComponentBuilder.FormatRetention.NONE).color(getSeverity(violationLevel)._color);
return new ChatComponentText(_friendlyName).setChatModifier(new ChatModifier().setColor(color));
} }
public Severity getSeverity(int violationLevel) public Severity getSeverity(int violationLevel)
@ -51,14 +52,14 @@ public class CheckThresholds
public enum Severity public enum Severity
{ {
NONE(EnumChatFormat.GREEN), NONE(ChatColor.GREEN),
LOW(EnumChatFormat.GREEN), LOW(ChatColor.GREEN),
MEDIUM(EnumChatFormat.GOLD), MEDIUM(ChatColor.GOLD),
HIGH(EnumChatFormat.RED), HIGH(ChatColor.RED),
; ;
private final EnumChatFormat _color; private final ChatColor _color;
Severity(EnumChatFormat color) Severity(ChatColor color)
{ {
_color = color; _color = color;
} }

View File

@ -1,8 +0,0 @@
package mineplex.core.antihack;
import org.bukkit.entity.Player;
public interface Detector
{
public void Reset(Player player);
}

View File

@ -0,0 +1,50 @@
package mineplex.core.antihack;
import net.minecraft.server.v1_8_R3.MinecraftServer;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import com.mineplex.anticheat.api.MineplexLink;
import mineplex.core.Managers;
import mineplex.core.common.util.UtilPlayer;
import mineplex.core.disguise.DisguiseManager;
import mineplex.core.disguise.disguises.DisguiseBase;
public class MineplexLinkImpl implements MineplexLink
{
private final DisguiseManager _disguiseManager = Managers.require(DisguiseManager.class);
@Override
public EntityType getActiveDisguise(Player player)
{
DisguiseBase disguise = _disguiseManager.getActiveDisguise(player);
return disguise != null ? disguise.getDisguiseType() : null;
}
@Override
public boolean isSpectator(Player player)
{
return UtilPlayer.isSpectator(player);
}
@Override
public double getTPS()
{
return MinecraftServer.getServer().recentTps[0]; // Return the average TPS from the last minute
}
@Override
public int getPing(Player player)
{
return Math.min(((CraftPlayer) player).getHandle().ping, 1000);
}
@Override
public boolean isUsingItem(Player player)
{
return ((CraftPlayer) player).getHandle().bS(); // See Anticheat javadoc
}
}

View File

@ -0,0 +1,87 @@
package mineplex.core.antihack;
import com.mineplex.anticheat.checks.Check;
import com.mineplex.anticheat.checks.CheckManager;
import gnu.trove.map.TObjectIntMap;
import gnu.trove.map.hash.TObjectIntHashMap;
/**
* Locally cached information about a user's max violations and total number of alerts for each
* check type.
* <p>
* Instances of this have no concept of identity i.e. account id is not tracked by this.
*/
public class ViolationLevels
{
private final TObjectIntMap<Class<? extends Check>> _maxViolations;
private final TObjectIntMap<Class<? extends Check>> _totalAlerts;
private final TObjectIntMap<Class<? extends Check>> _lastBan;
public ViolationLevels()
{
_maxViolations = new TObjectIntHashMap<>(CheckManager.AVAILABLE_CHECKS.size());
_totalAlerts = new TObjectIntHashMap<>(CheckManager.AVAILABLE_CHECKS.size());
_lastBan = new TObjectIntHashMap<>(CheckManager.AVAILABLE_CHECKS.size());
}
public void updateMaxViolations(Class<? extends Check> check, int violationLevel)
{
if (violationLevel > _maxViolations.get(check))
{
_maxViolations.put(check, violationLevel);
}
}
public void updateMaxViolationsSinceLastBan(Class<? extends Check> check, int violationLevel)
{
if (violationLevel > _lastBan.get(check))
{
_lastBan.put(check, violationLevel);
}
}
public void incrementAlerts(Class<? extends Check> check)
{
int cur = _totalAlerts.get(check);
setTotalAlerts(check, cur + 1);
}
public void setTotalAlerts(Class<? extends Check> check, int totalAlerts)
{
_totalAlerts.put(check, totalAlerts);
}
public int getTotalAlertsForCheck(Class<? extends Check> check)
{
if (_totalAlerts.containsKey(check))
{
return _totalAlerts.get(check);
}
return -1;
}
public int getMaxViolationsForCheck(Class<? extends Check> check)
{
if (_maxViolations.containsKey(check))
{
return _maxViolations.get(check);
}
return -1;
}
public int getLastBanViolationsForCheck(Class<? extends Check> check)
{
if (_lastBan.containsKey(check))
{
return _lastBan.get(check);
}
return -1;
}
}

View File

@ -4,6 +4,7 @@ import com.mineplex.anticheat.api.PlayerViolationEvent;
import com.mineplex.anticheat.checks.combat.KillauraTypeA; import com.mineplex.anticheat.checks.combat.KillauraTypeA;
import com.mineplex.anticheat.checks.combat.KillauraTypeD; import com.mineplex.anticheat.checks.combat.KillauraTypeD;
import com.mineplex.anticheat.checks.move.Glide; import com.mineplex.anticheat.checks.move.Glide;
import com.mineplex.anticheat.checks.move.HeadRoll;
import com.mineplex.anticheat.checks.move.Speed; import com.mineplex.anticheat.checks.move.Speed;
import mineplex.core.common.util.UtilServer; import mineplex.core.common.util.UtilServer;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
@ -13,40 +14,19 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public abstract class AntiHackAction implements Listener public abstract class AntiHackAction
{ {
private static final Map<Class<?>, AntiHackAction> ACTIONS = new HashMap<>(); private final int _vl;
private static final AntiHackAction NOOP_ACTION = new NoopAction();
private static final Date NEXT_BAN_WAVE = new Date(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(5));
static
{
ACTIONS.put(KillauraTypeA.class, new ImmediateBanAction(200));
ACTIONS.put(KillauraTypeD.class, new BanwaveAction(2000));
ACTIONS.put(Glide.class, new ImmediateBanAction(10000));
ACTIONS.put(Speed.class, new ImmediateBanAction(10000));
}
private int _vl;
AntiHackAction(int vl) AntiHackAction(int vl)
{ {
this._vl = vl; this._vl = vl;
UtilServer.RegisterEvents(this);
} }
public abstract void handle(PlayerViolationEvent event); public final int getMinVl()
public int getMinVl()
{ {
return this._vl; return this._vl;
} }
public static AntiHackAction getAction(Class<?> checkClass) public abstract void handle(PlayerViolationEvent event);
{
AntiHackAction action = ACTIONS.getOrDefault(checkClass, NOOP_ACTION);
return action;
}
} }

View File

@ -1,17 +1,18 @@
package mineplex.core.antihack.actions; package mineplex.core.antihack.actions;
import com.mineplex.anticheat.api.PlayerViolationEvent; import com.mineplex.anticheat.api.PlayerViolationEvent;
import mineplex.core.Managers; import mineplex.core.Managers;
import mineplex.core.antihack.banwave.BanWaveManager; import mineplex.core.antihack.banwave.BanWaveManager;
import mineplex.core.common.util.UtilMath; import mineplex.core.common.util.UtilMath;
import mineplex.core.common.util.UtilServer; import mineplex.core.common.util.UtilServer;
class BanwaveAction extends AntiHackAction public class BanwaveAction extends AntiHackAction
{ {
private static final int BAN_DELAY_AVERAGE = 6 * 60 * 60 * 1000; // 6 hours private static final int BAN_DELAY_AVERAGE = 6 * 60 * 60 * 1000; // 6 hours
private static final int BAN_DELAY_VARIANCE_SPAN = 4 * 60 * 60 * 1000; // 4 hours total; 2 on either side private static final int BAN_DELAY_VARIANCE_SPAN = 4 * 60 * 60 * 1000; // 4 hours total; 2 on either side
BanwaveAction(int vl) public BanwaveAction(int vl)
{ {
super(vl); super(vl);
} }
@ -27,7 +28,6 @@ class BanwaveAction extends AntiHackAction
event.getPlayer(), event.getPlayer(),
banTime, banTime,
event.getCheckClass(), event.getCheckClass(),
"[GWEN] Hacking [BanWave]",
event.getViolations(), event.getViolations(),
UtilServer.getServerName() UtilServer.getServerName()
); );

View File

@ -5,9 +5,9 @@ import mineplex.core.Managers;
import mineplex.core.antihack.AntiHack; import mineplex.core.antihack.AntiHack;
import mineplex.core.common.util.UtilServer; import mineplex.core.common.util.UtilServer;
class ImmediateBanAction extends AntiHackAction public class ImmediateBanAction extends AntiHackAction
{ {
ImmediateBanAction(int vl) public ImmediateBanAction(int vl)
{ {
super(vl); super(vl);
} }
@ -17,12 +17,7 @@ class ImmediateBanAction extends AntiHackAction
{ {
if (event.getViolations() >= this.getMinVl()) if (event.getViolations() >= this.getMinVl())
{ {
String server = UtilServer.getServerName(); Managers.get(AntiHack.class).doBan(event.getPlayer(), event.getCheckClass());
if (server.contains("-"))
{
server = server.substring(0, server.indexOf('-'));
}
Managers.get(AntiHack.class).doBan(event.getPlayer(), "[GWEN] Hacking [" + server + "]");
} }
} }
} }

View File

@ -1,49 +0,0 @@
package mineplex.core.antihack.actions;
import com.mineplex.anticheat.api.PlayerViolationEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
public class MixedAction extends AntiHackAction
{
private List<AntiHackAction> _actions = new ArrayList<>();
private Map<UUID, Set<AntiHackAction>> _punished = new HashMap<>();
public MixedAction(AntiHackAction firstAction, AntiHackAction... actions)
{
super(firstAction.getMinVl());
this._actions.add(firstAction);
this._actions.addAll(Arrays.asList(actions));
}
@Override
public void handle(PlayerViolationEvent event)
{
for (int i = this._actions.size() - 1; i >= 0; i--)
{
AntiHackAction action = this._actions.get(i);
if (action.getMinVl() <= event.getViolations())
{
if (_punished.computeIfAbsent(event.getPlayer().getUniqueId(), key -> new HashSet<>()).add(action))
{
action.handle(event);
}
break;
}
}
}
public int getMinVl()
{
return this._actions.get(0).getMinVl();
}
}

View File

@ -4,7 +4,7 @@ import com.mineplex.anticheat.api.PlayerViolationEvent;
public class NoopAction extends AntiHackAction public class NoopAction extends AntiHackAction
{ {
NoopAction() public NoopAction()
{ {
super(Integer.MAX_VALUE); super(Integer.MAX_VALUE);
} }

View File

@ -0,0 +1,9 @@
package mineplex.core.antihack.animations;
import mineplex.core.antihack.AntiHack;
import org.bukkit.entity.Player;
public interface BanwaveAnimation
{
void run(Player player, Runnable after);
}

View File

@ -0,0 +1,123 @@
package mineplex.core.antihack.animations;
import com.google.common.util.concurrent.AtomicDouble;
import mineplex.core.antihack.AntiHack;
import mineplex.core.antihack.guardians.AntiHackGuardian;
import mineplex.core.common.util.UtilEnt;
import mineplex.core.common.util.UtilParticle;
import mineplex.core.common.util.UtilServer;
import net.minecraft.server.v1_8_R3.MathHelper;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
public class BanwaveAnimationSpin implements BanwaveAnimation
{
@Override
public void run(Player player, Runnable after)
{
float oldWalkSpeed = player.getWalkSpeed();
player.setWalkSpeed(0);
player.addPotionEffect(new PotionEffect(PotionEffectType.JUMP, 999999, -10));
double radius = 4;
double heightAdj = 8;
double baseDeg = 18;
Location center = player.getLocation().add(0, heightAdj, 0);
AntiHackGuardian north = new AntiHackGuardian(center.clone().add(0, 0, -radius), 0, 0, 0, 0, 0, 0, false);
AntiHackGuardian east = new AntiHackGuardian(center.clone().add(radius, 0, 0), 0, 0, 0, 0, 0, 0, false);
AntiHackGuardian south = new AntiHackGuardian(center.clone().add(0, 0, radius), 0, 0, 0, 0, 0, 0, false);
AntiHackGuardian west = new AntiHackGuardian(center.clone().add(-radius, 0, 0), 0, 0, 0, 0, 0, 0, false);
UtilEnt.CreatureLook(east.getEntity(), player);
UtilEnt.CreatureLook(west.getEntity(), player);
UtilEnt.CreatureLook(south.getEntity(), player);
UtilEnt.CreatureLook(north.getEntity(), player);
Function<Double, Double> magic = seconds -> Math.pow(2, seconds - 5);
UtilServer.runSyncLater(() ->
{
north.shoot(player);
east.shoot(player);
south.shoot(player);
west.shoot(player);
// We get 5 seconds, or 100 ticks
AtomicInteger timer = new AtomicInteger(5);
AtomicDouble cNorth = new AtomicDouble(270);
AtomicDouble cEast = new AtomicDouble(0);
AtomicDouble cSouth = new AtomicDouble(90);
AtomicDouble cWest = new AtomicDouble(180);
UtilServer.runSyncTimer(new BukkitRunnable()
{
public void run()
{
timer.getAndIncrement();
if (timer.get() > 100)
{
cancel();
player.removePotionEffect(PotionEffectType.JUMP);
player.setWalkSpeed(oldWalkSpeed);
Location location = player.getLocation();
UtilParticle.PlayParticle(UtilParticle.ParticleType.HUGE_EXPLOSION, player.getLocation(), 3f, 3f, 3f, 0, 32, UtilParticle.ViewDist.MAX, UtilServer.getPlayers());
after.run();
north.shoot(null);
south.shoot(null);
east.shoot(null);
west.shoot(null);
UtilEnt.CreatureLook(north.getEntity(), location);
UtilEnt.CreatureLook(south.getEntity(), location);
UtilEnt.CreatureLook(east.getEntity(), location);
UtilEnt.CreatureLook(west.getEntity(), location);
UtilServer.runSyncLater(() ->
{
north.remove();
south.remove();
east.remove();
west.remove();
}, 40L);
return;
}
double seconds = timer.get() / 20.0;
double rate = magic.apply(seconds) * 3 * baseDeg;
player.getLocation(center);
center.add(0, heightAdj, 0);
{
cNorth.addAndGet(rate);
north.move(center.getX() + radius * MathHelper.cos((float) Math.toRadians(cNorth.get())), center.getY(), center.getZ() + radius * MathHelper.sin((float) Math.toRadians(cNorth.get())));
}
{
cSouth.addAndGet(rate);
south.move(center.getX() + radius * MathHelper.cos((float) Math.toRadians(cSouth.get())), center.getY(), center.getZ() + radius * MathHelper.sin((float) Math.toRadians(cSouth.get())));
}
{
cEast.addAndGet(rate);
east.move(center.getX() + radius * MathHelper.cos((float) Math.toRadians(cEast.get())), center.getY(), center.getZ() + radius * MathHelper.sin((float) Math.toRadians(cEast.get())));
}
{
cWest.addAndGet(rate);
west.move(center.getX() + radius * MathHelper.cos((float) Math.toRadians(cWest.get())), center.getY(), center.getZ() + radius * MathHelper.sin((float) Math.toRadians(cWest.get())));
}
}
}, 5L, 1L);
}, 20);
}
}

View File

@ -34,6 +34,11 @@ public class BanWaveInfo
*/ */
private String _server; private String _server;
/**
* The metadata id
*/
private String _metadata;
public int getAccountId() public int getAccountId()
{ {
return _accountId; return _accountId;
@ -94,6 +99,16 @@ public class BanWaveInfo
_server = server; _server = server;
} }
public String getMetadataId()
{
return this._metadata;
}
public void setMetadataId(String id)
{
this._metadata = id;
}
@Override @Override
public boolean equals(Object o) public boolean equals(Object o)
{ {

View File

@ -5,14 +5,25 @@ import mineplex.core.ReflectivelyCreateMiniPlugin;
import mineplex.core.account.CoreClient; import mineplex.core.account.CoreClient;
import mineplex.core.account.CoreClientManager; import mineplex.core.account.CoreClientManager;
import mineplex.core.antihack.AntiHack; import mineplex.core.antihack.AntiHack;
import mineplex.core.antihack.logging.AntihackLogger;
import mineplex.core.antihack.redisnotifications.GwenBanwaveNotification;
import mineplex.core.common.util.UtilServer;
import mineplex.serverdata.commands.ServerCommandManager;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerJoinEvent;
import com.google.gson.JsonObject;
import com.mineplex.anticheat.checks.Check;
import com.mineplex.anticheat.checks.CheckManager;
@ReflectivelyCreateMiniPlugin @ReflectivelyCreateMiniPlugin
public class BanWaveManager extends MiniPlugin public class BanWaveManager extends MiniPlugin
{ {
private final BanWaveRepository _repository = new BanWaveRepository(); private final BanWaveRepository _repository = new BanWaveRepository();
private final CoreClientManager _clientManager = require(CoreClientManager.class);
private BanWaveManager() private BanWaveManager()
{ {
@ -32,29 +43,39 @@ public class BanWaveManager extends MiniPlugin
if (info.getTimeToBan() < now) if (info.getTimeToBan() < now)
{ {
require(AntiHack.class).doBanWave(event.getPlayer(), info.getMessage()); require(AntiHack.class).doBanWave(event.getPlayer(), info);
_repository.flagDone(info); _repository.flagDone(info);
} }
}); });
}); });
} }
public void insertBanWaveInfo(Player player, long timeToBan, Class<?> checkClass, String message, int vl, String server) public void insertBanWaveInfo(Player player, long timeToBan, Class<? extends Check> checkClass, int vl, String server)
{ {
insertBanWaveInfo(player, timeToBan, checkClass, message, vl, server, null); insertBanWaveInfo(player, timeToBan, checkClass, vl, server, null);
} }
public void insertBanWaveInfo(Player player, long timeToBan, Class<?> checkClass, String message, int vl, String server, Runnable after) public void insertBanWaveInfo(Player player, long timeToBan, Class<? extends Check> checkClass, int vl, String server, Runnable after)
{ {
runAsync(() -> runAsync(() ->
{ {
CoreClient client = require(CoreClientManager.class).Get(player); String id = AntiHack.generateId();
String newMessage = "[GWEN] [BanWave] " + id;
this._repository.insertBanWaveInfo(client.getAccountId(), timeToBan, checkClass.getName(), message, vl, server); CoreClient client = _clientManager.Get(player);
if (after != null) if (this._repository.insertBanWaveInfo(client.getAccountId(), timeToBan, CheckManager.getCheckSimpleName(checkClass), newMessage, vl, server, id))
{ {
after.run(); runAsync(() ->
{
GwenBanwaveNotification notification = new GwenBanwaveNotification(UtilServer.getServerName(), player.getName(), player.getUniqueId().toString(), CheckManager.getCheckSimpleName(checkClass), id, timeToBan);
ServerCommandManager.getInstance().publishCommand(notification);
});
JsonObject custom = new JsonObject();
custom.addProperty("is-banwave", true);
require(AntihackLogger.class).saveMetadata(player, id, after, custom);
} }
}); });
} }

View File

@ -17,6 +17,7 @@ public class BanWaveRepository extends MinecraftRepository
"message VARCHAR(255), " + "message VARCHAR(255), " +
"vl INT, " + "vl INT, " +
"server VARCHAR(32), " + "server VARCHAR(32), " +
"metadata VARCHAR(10), " +
"PRIMARY KEY (accountId)," + "PRIMARY KEY (accountId)," +
"FOREIGN KEY (accountId) REFERENCES accounts(id))"; "FOREIGN KEY (accountId) REFERENCES accounts(id))";
@ -28,12 +29,14 @@ public class BanWaveRepository extends MinecraftRepository
"message VARCHAR(255), " + "message VARCHAR(255), " +
"vl INT, " + "vl INT, " +
"server VARCHAR(32), " + "server VARCHAR(32), " +
"metadata VARCHAR(10), " +
"PRIMARY KEY (id)," + "PRIMARY KEY (id)," +
"FOREIGN KEY (accountId) REFERENCES accounts(id))"; "FOREIGN KEY (accountId) REFERENCES accounts(id))";
private static final String QUERY_PENDING = "SELECT * FROM banwavePending WHERE accountId = ?";
private static final String INSERT_PENDING = "INSERT IGNORE INTO banwavePending (accountId, timeToBan, hacktype, message, vl, server) VALUES (?, ?, ?, ?, ?, ?)";
private static final String PROCESS_WAVE_FOR_ACCOUNT = "INSERT INTO banwaveProcessed SELECT 0, accountId, timeToBan, hacktype, message, vl, server FROM banwavePending WHERE accountId = ?"; private static final String QUERY_PENDING = "SELECT * FROM banwavePending WHERE accountId = ?";
private static final String INSERT_PENDING = "INSERT IGNORE INTO banwavePending (accountId, timeToBan, hacktype, message, vl, server, metadata) VALUES (?, ?, ?, ?, ?, ?, ?)";
private static final String PROCESS_WAVE_FOR_ACCOUNT = "INSERT INTO banwaveProcessed SELECT 0, accountId, timeToBan, hacktype, message, vl, server, metadata FROM banwavePending WHERE accountId = ?";
private static final String DELETE_PENDING = "DELETE FROM banwavePending WHERE accountId = ?"; private static final String DELETE_PENDING = "DELETE FROM banwavePending WHERE accountId = ?";
BanWaveRepository() BanWaveRepository()
@ -66,22 +69,25 @@ public class BanWaveRepository extends MinecraftRepository
info.setMessage(resultSet.getString(4)); info.setMessage(resultSet.getString(4));
info.setVl(resultSet.getInt(5)); info.setVl(resultSet.getInt(5));
info.setServer(resultSet.getString(6)); info.setServer(resultSet.getString(6));
info.setMessage(resultSet.getString(7));
callback.run(info); callback.run(info);
} }
}, new ColumnInt("accountId", accountId)); }, new ColumnInt("accountId", accountId));
} }
void insertBanWaveInfo(int accountId, long timeToBan, String hackType, String message, int vl, String server) boolean insertBanWaveInfo(int accountId, long timeToBan, String hackType, String message, int vl, String server, String metadata)
{ {
executeInsert(INSERT_PENDING, null, int affectedRows = executeInsert(INSERT_PENDING, null,
new ColumnInt("accountId", accountId), new ColumnInt("accountId", accountId),
new ColumnLong("timeToBan", timeToBan), new ColumnLong("timeToBan", timeToBan),
new ColumnVarChar("hacktype", 64, hackType), new ColumnVarChar("hacktype", 64, hackType),
new ColumnVarChar("message", 255, message), new ColumnVarChar("message", 255, message),
new ColumnInt("vl", vl), new ColumnInt("vl", vl),
new ColumnVarChar("server", 32, server) new ColumnVarChar("server", 32, server),
new ColumnVarChar("metadata", 10, metadata)
); );
return affectedRows > 0;
} }
void flagDone(BanWaveInfo info) void flagDone(BanWaveInfo info)

View File

@ -0,0 +1,24 @@
package mineplex.core.antihack.commands;
import org.bukkit.entity.Player;
import mineplex.core.antihack.AntiHack;
import mineplex.core.command.CommandBase;
import mineplex.core.common.Rank;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilPlayer;
public class AnticheatOffCommand extends CommandBase<AntiHack>
{
public AnticheatOffCommand(AntiHack plugin)
{
super(plugin, Rank.DEVELOPER, "acoff");
}
@Override
public void Execute(Player caller, String[] args)
{
Plugin.disableAnticheat();
UtilPlayer.message(caller, F.main(Plugin.getName(), "Disabled anticheat"));
}
}

View File

@ -0,0 +1,24 @@
package mineplex.core.antihack.commands;
import org.bukkit.entity.Player;
import mineplex.core.antihack.AntiHack;
import mineplex.core.command.CommandBase;
import mineplex.core.common.Rank;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilPlayer;
public class AnticheatOnCommand extends CommandBase<AntiHack>
{
public AnticheatOnCommand(AntiHack plugin)
{
super(plugin, Rank.DEVELOPER, "acon");
}
@Override
public void Execute(Player caller, String[] args)
{
Plugin.enableAnticheat();
UtilPlayer.message(caller, F.main(Plugin.getName(), "Enabled anticheat"));
}
}

View File

@ -0,0 +1,30 @@
package mineplex.core.antihack.commands;
import org.bukkit.entity.Player;
import mineplex.core.antihack.AntiHack;
import mineplex.core.command.CommandBase;
import mineplex.core.common.Rank;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilPlayer;
public class DetailedMessagesCommand extends CommandBase<AntiHack>
{
public DetailedMessagesCommand(AntiHack plugin)
{
super(plugin, Rank.DEVELOPER, "detailedmessages");
}
@Override
public void Execute(Player caller, String[] args)
{
if (Plugin.toggleDetailedMessage(caller))
{
UtilPlayer.message(caller, F.main(Plugin.getName(), "Detailed messages enabled"));
}
else
{
UtilPlayer.message(caller, F.main(Plugin.getName(), "Detailed messages disabled"));
}
}
}

View File

@ -0,0 +1,47 @@
package mineplex.core.antihack.commands;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import com.mineplex.anticheat.MineplexAnticheat;
import com.mineplex.anticheat.checks.Check;
import com.mineplex.anticheat.checks.CheckManager;
import mineplex.core.antihack.AntiHack;
import mineplex.core.command.CommandBase;
import mineplex.core.common.Rank;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilPlayer;
public class GetVlsCommand extends CommandBase<AntiHack>
{
public GetVlsCommand(AntiHack plugin)
{
super(plugin, Rank.DEVELOPER, "getvls");
}
@Override
public void Execute(Player caller, String[] args)
{
if (args.length > 0)
{
Player p = Bukkit.getPlayerExact(args[0]);
if (p != null)
{
CheckManager manager = MineplexAnticheat.getPlugin(MineplexAnticheat.class).getCheckManager();
for (Check check : manager.getActiveChecks())
{
UtilPlayer.message(caller, F.desc(check.getName(), String.valueOf(check.getViolationLevel(p))));
}
}
else
{
UtilPlayer.message(caller, F.main(Plugin.getName(), "Could not find player"));
}
}
else
{
UtilPlayer.message(caller, F.main(Plugin.getName(), "No player specified"));
}
}
}

View File

@ -0,0 +1,51 @@
package mineplex.core.antihack.commands;
import java.util.concurrent.ThreadLocalRandom;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import mineplex.core.antihack.AntiHack;
import mineplex.core.antihack.animations.BanwaveAnimationSpin;
import mineplex.core.command.CommandBase;
import mineplex.core.common.Rank;
import mineplex.core.common.util.C;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilPlayer;
public class TestBanCommand extends CommandBase<AntiHack>
{
public TestBanCommand(AntiHack plugin)
{
super(plugin, Rank.DEVELOPER, "testban");
}
@Override
public void Execute(Player caller, String[] args)
{
if (args.length > 0)
{
Player p = Bukkit.getPlayerExact(args[0]);
if (p != null)
{
new BanwaveAnimationSpin().run(p, () ->
{
String reason = C.cRed + C.Bold + "You are banned for permanent by Test" +
"\n" + C.cWhite + "Seems to be speeding up time. (" + ThreadLocalRandom.current().nextInt(200, 400) + " packets/150 ms)" +
"\n" + C.cDGreen + "Unfairly banned? Appeal at " + C.cGreen + "www.mineplex.com/appeals";
p.kickPlayer(reason);
Plugin.announceBan(p);
});
}
else
{
UtilPlayer.message(caller, F.main(Plugin.getName(), "Could not find player"));
}
}
else
{
UtilPlayer.message(caller, F.main(Plugin.getName(), "No player specified"));
}
}
}

View File

@ -1,4 +1,4 @@
package mineplex.core.antihack; package mineplex.core.antihack.guardians;
import com.mineplex.spigot.ChunkAddEntityEvent; import com.mineplex.spigot.ChunkAddEntityEvent;
import mineplex.core.Managers; import mineplex.core.Managers;

View File

@ -0,0 +1,129 @@
package mineplex.core.antihack.guardians;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import mineplex.core.MiniPlugin;
import mineplex.core.PlayerSelector;
import mineplex.core.ReflectivelyCreateMiniPlugin;
import mineplex.core.common.Rank;
import mineplex.core.common.util.UtilLambda;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
@ReflectivelyCreateMiniPlugin
public class GuardianManager extends MiniPlugin
{
private static final int MAX_STALKED_PLAYERS = 3;
private static final int STALK_COOLDOWN_TIME_SECONDS = 5;
private static final int MIN_STALK_TIME = 10 * 20;
private static final int MAX_STALK_TIME = 20 * 20;
private static final int MAX_MIN_DIFF = MAX_STALK_TIME - MIN_STALK_TIME;
private static final Function<Integer, Double> STALK_END_PROBABILITY_EQUATION = x ->
{
return 1.0/ MAX_MIN_DIFF * x; // linear equation with points (0, 0) and (diff, 1)
};
private final Cache<UUID, Boolean> _stalkingCooldown = CacheBuilder.newBuilder()
.concurrencyLevel(1)
.expireAfterWrite(STALK_COOLDOWN_TIME_SECONDS, TimeUnit.SECONDS)
.build();
private final List<UUID> _stalking = new ArrayList<>();
private List<AntiHackGuardian> _guardians = new ArrayList<>();
private GuardianManager()
{
super("GuardianManager");
this._plugin.getServer().getScheduler().runTaskTimer(this._plugin, () ->
{
for (AntiHackGuardian guardian : this._guardians)
{
if (guardian.getTarget() != null && !guardian.getTarget().isOnline())
{
this._stalking.remove(guardian.getTarget().getUniqueId());
guardian.stopTargeting();
}
else if (guardian.getTargetingTime() > MIN_STALK_TIME)
{
double threshold = STALK_END_PROBABILITY_EQUATION.apply(guardian.getTargetingTime() - MIN_STALK_TIME);
if (Math.random() <= threshold)
{
this._stalking.remove(guardian.getTarget().getUniqueId());
_stalkingCooldown.put(guardian.getTarget().getUniqueId(), true);
guardian.stopTargeting();
}
}
guardian.tick();
}
}, 0L, 1L);
this._plugin.getServer().getScheduler().runTaskTimer(this._plugin, () ->
{
if (_stalking.size() >= MAX_STALKED_PLAYERS)
{
return;
}
if (_guardians.size() == 0)
{
return;
}
List<Player> targets = PlayerSelector.selectPlayers(
UtilLambda.and(
PlayerSelector.NOT_VANISHED,
PlayerSelector.hasAnyRank(false,
Rank.ALL,
Rank.ULTRA,
Rank.HERO,
Rank.LEGEND,
Rank.TITAN,
Rank.TWITCH,
Rank.YOUTUBE_SMALL,
Rank.YOUTUBE,
Rank.MEDIA,
Rank.ADMIN,
Rank.DEVELOPER,
Rank.OWNER,
Rank.LT
),
player -> !_stalking.contains(player.getUniqueId()),
player -> _stalkingCooldown.getIfPresent(player.getUniqueId()) == null
));
while (_stalking.size() < MAX_STALKED_PLAYERS && targets.size() > 0)
{
Player target = targets.remove(ThreadLocalRandom.current().nextInt(targets.size()));
int start = ThreadLocalRandom.current().nextInt(_guardians.size());
for (int i = start, j = 0; j < _guardians.size(); i++, j++)
{
if (i >= _guardians.size())
{
i -= _guardians.size();
}
AntiHackGuardian guardian = _guardians.get(i);
if (!guardian.isTargeting())
{
guardian.target(target);
_stalking.add(target.getUniqueId());
break;
}
}
}
}, 0L, 20L);
}
public void registerGuardian(AntiHackGuardian guardian)
{
this._guardians.add(guardian);
}
}

View File

@ -0,0 +1,196 @@
package mineplex.core.antihack.logging;
import com.mineplex.anticheat.checks.Check;
import com.mineplex.anticheat.checks.CheckManager;
import gnu.trove.map.TIntObjectMap;
import mineplex.core.antihack.ViolationLevels;
import mineplex.core.database.MinecraftRepository;
import mineplex.serverdata.database.DBPool;
import org.bukkit.plugin.java.JavaPlugin;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import java.util.Optional;
public class AnticheatDatabase extends MinecraftRepository
{
/*
CREATE TABLE IF NOT EXISTS anticheat_vl_logs (accountId INT, checkId INT, maxViolations INT, totalAlerts INT, sinceLastBan INT, PRIMARY KEY(accountId, checkId));
CREATE TABLE IF NOT EXISTS anticheat_ban_metadata (id INT NOT NULL AUTO_INCREMENT, accountId INT, banId CHAR(10) NOT NULL, data MEDIUMTEXT NOT NULL, PRIMARY KEY(id));
*/
private static final String INSERT_INTO_METADATA = "INSERT INTO anticheat_ban_metadata (accountId, banId, data) VALUES (?, ?, ?);";
private static final String UPDATE_VIOLATIONS = "INSERT INTO anticheat_vl_logs (accountId, checkId, "
+ "maxViolations, sinceLastBan, totalAlerts) VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY"
+ " UPDATE maxViolations = VALUES(maxViolations), totalAlerts = VALUES(totalAlerts), sinceLastBan = VALUES(sinceLastBan);";
private static final String CLEAR_LAST_BAN_VIOLATIONS = "UPDATE anticheat_vl_logs SET sinceLastBan = 0 WHERE accountId = ?;";
private static final String GET_VLS = "SELECT checkId, maxViolations, sinceLastBan, totalAlerts FROM anticheat_vl_logs";
private static final String GET_VLS_BY_ACCOUNT_ID = GET_VLS + " WHERE accountId = ?";
private static final String GET_VLS_FOR_CHECK = GET_VLS + " WHERE checkId = ? AND accountId = ?";
public AnticheatDatabase(JavaPlugin plugin)
{
super(plugin, DBPool.getAccount());
}
/**
* Submit a set of user violation changes batch style.
*
* @param uploadQueue the {@link TIntObjectMap} describing the changes.
*/
public void saveViolationLevels(Map<Integer, ViolationLevels> uploadQueue)
{
try (Connection connection = getConnection())
{
PreparedStatement preparedStatement = connection.prepareStatement(UPDATE_VIOLATIONS);
uploadQueue.forEach((accountId, vls) ->
{
CheckManager.AVAILABLE_CHECKS.values().forEach(check ->
{
int checkId = CheckManager.getCheckId(check),
maxVls = vls.getMaxViolationsForCheck(check),
maxVlsSinceLastBan = vls.getLastBanViolationsForCheck(check),
totalAlerts = vls.getTotalAlertsForCheck(check);
// if neither value has been set don't store anything
if (maxVls < 0 && totalAlerts < 0 && maxVlsSinceLastBan < 0)
{
return;
}
maxVls = Math.max(maxVls, 0);
maxVlsSinceLastBan = Math.max(maxVlsSinceLastBan, 0);
totalAlerts = Math.max(totalAlerts, 0);
try
{
preparedStatement.setInt(1, accountId);
preparedStatement.setInt(2, checkId);
preparedStatement.setInt(3, maxVls);
preparedStatement.setInt(4, maxVlsSinceLastBan);
preparedStatement.setInt(5, totalAlerts);
preparedStatement.addBatch();
}
catch (SQLException e)
{
e.printStackTrace();
}
});
});
preparedStatement.executeBatch();
}
catch (SQLException ex)
{
ex.printStackTrace();
}
}
/**
* Attempts to retrieve violation levels for the given account id.
*
* @param accountId The account id;
* @return an {@link Optional} describing the user's violation levels, or an empty one if none
* are found.
* @throws SQLException On failing to connect to the database.
*/
public Optional<ViolationLevels> getViolationLevels(int accountId)
{
ViolationLevels levels = new ViolationLevels();
try (Connection connection = getConnection())
{
PreparedStatement statement = connection.prepareStatement(GET_VLS_BY_ACCOUNT_ID);
statement.setInt(1, accountId);
ResultSet result = statement.executeQuery();
while (result.next())
{
int checkId = result.getInt("checkId");
Class<? extends Check> checkType = CheckManager.getCheckById(checkId);
if (checkType == null)
{
System.err.println("Whoops. Unintended refactor?");
continue;
}
levels.updateMaxViolations(checkType, result.getInt("maxViolations"));
levels.updateMaxViolationsSinceLastBan(checkType, result.getInt("sinceLastBan"));
levels.setTotalAlerts(checkType, result.getInt("totalAlerts"));
}
}
catch (SQLException ex)
{
ex.printStackTrace();
}
return Optional.of(levels);
}
public void clearLastBan(int accountId, Runnable after)
{
try (Connection connection = getConnection())
{
PreparedStatement statement = connection.prepareStatement(CLEAR_LAST_BAN_VIOLATIONS);
statement.setInt(1, accountId);
statement.executeUpdate();
}
catch (SQLException e)
{
e.printStackTrace();
}
finally
{
if (after != null)
after.run();
}
}
public void saveMetadata(int accountId, String id, String base64, Runnable after)
{
try (Connection connection = getConnection())
{
PreparedStatement statement = connection.prepareStatement(INSERT_INTO_METADATA);
statement.setInt(1, accountId);
statement.setString(2, id);
statement.setString(3, base64);
statement.executeUpdate();
}
catch (SQLException ex)
{
ex.printStackTrace();
}
finally
{
if (after != null)
after.run();
}
}
@Override
protected void initialize()
{
}
@Override
protected void update()
{
}
}

View File

@ -0,0 +1,23 @@
package mineplex.core.antihack.logging;
import java.util.UUID;
import org.bukkit.event.Listener;
import com.google.gson.JsonElement;
import mineplex.core.common.util.UtilServer;
public abstract class AnticheatMetadata implements Listener
{
public AnticheatMetadata()
{
UtilServer.RegisterEvents(this);
}
public abstract String getId();
public abstract JsonElement build(UUID player);
public abstract void remove(UUID player);
}

View File

@ -0,0 +1,214 @@
package mineplex.core.antihack.logging;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.tukaani.xz.LZMA2Options;
import org.tukaani.xz.XZ;
import org.tukaani.xz.XZOutputStream;
import com.google.gson.Gson;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.mineplex.anticheat.api.PlayerViolationEvent;
import com.mineplex.anticheat.checks.Check;
import mineplex.core.MiniPlugin;
import mineplex.core.ReflectivelyCreateMiniPlugin;
import mineplex.core.account.CoreClientManager;
import mineplex.core.antihack.AntiHack;
import mineplex.core.antihack.ViolationLevels;
import mineplex.core.antihack.logging.builtin.PartyInfoMetadata;
import mineplex.core.antihack.logging.builtin.PlayerInfoMetadata;
import mineplex.core.antihack.logging.builtin.ServerInfoMetadata;
import mineplex.core.antihack.logging.builtin.ViolationInfoMetadata;
import mineplex.core.command.CommandBase;
import mineplex.core.common.Rank;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilPlayer;
import mineplex.core.common.util.UtilServer;
@ReflectivelyCreateMiniPlugin
public class AntihackLogger extends MiniPlugin
{
public static final Gson GSON = new Gson();
private static final int PUSH_QUEUE_TIME_IN_SECONDS = 60;
private final CoreClientManager _clientManager = require(CoreClientManager.class);
private final Map<Integer, ViolationLevels> _violationLevels = new ConcurrentHashMap<>();
private final Map<String, AnticheatMetadata> _metadata = new HashMap<>();
private final AnticheatDatabase _db;
private AntihackLogger()
{
super("AnticheatPlugin");
_db = new AnticheatDatabase(getPlugin());
runSyncTimer(this::pushQueuedViolationChanges, 20, 20 * PUSH_QUEUE_TIME_IN_SECONDS);
registerMetadata(new ServerInfoMetadata());
registerMetadata(new ViolationInfoMetadata());
registerMetadata(new PartyInfoMetadata());
registerMetadata(new PlayerInfoMetadata());
}
@Override
public void disable()
{
pushQueuedViolationChanges();
}
@EventHandler
public void addCommands()
{
if (UtilServer.isTestServer())
{
addCommand(new CommandBase<AntihackLogger>(this, Rank.SNR_MODERATOR, "savemetadata")
{
@Override
public void Execute(Player caller, String[] args)
{
if (args.length == 1)
{
Player player = Bukkit.getPlayer(args[0]);
if (player != null)
{
JsonObject custom = new JsonObject();
custom.addProperty("is-test-metadata", true);
String id = AntiHack.generateId();
saveMetadata(player, id, () ->
{
UtilPlayer.message(caller, F.main(getName(), "Saved metadata for " + player.getName() + " with id " + id));
}, custom);
}
}
}
});
}
}
private void pushQueuedViolationChanges()
{
Map<Integer, ViolationLevels> clone = new HashMap<>(_violationLevels);
runAsync(() -> _db.saveViolationLevels(clone));
}
@EventHandler
public void onCheckFail(PlayerViolationEvent event)
{
ViolationLevels playerVls = _violationLevels.get(_clientManager.getAccountId(event.getPlayer()));
Class<? extends Check> check = event.getCheckClass();
playerVls.updateMaxViolations(check, event.getViolations());
playerVls.updateMaxViolationsSinceLastBan(check, event.getViolations());
playerVls.incrementAlerts(check);
}
@EventHandler
public void onLoad(PlayerLoginEvent event)
{
runAsync(() ->
{
int accountId = _clientManager.getAccountId(event.getPlayer());
_db.getViolationLevels(accountId)
.ifPresent(vls ->
{
_violationLevels.put(accountId, vls);
});
});
}
@EventHandler
public void onQuit(PlayerQuitEvent event)
{
Player player = event.getPlayer();
int accountId =_clientManager.getAccountId(event.getPlayer());
ViolationLevels levels = _violationLevels.get(accountId);
if (levels != null)
{
Map<Integer, ViolationLevels> clone = new HashMap<>();
clone.put(accountId, levels);
runAsync(() -> _db.saveViolationLevels(clone));
}
_metadata.values().forEach(metadata -> metadata.remove(event.getPlayer().getUniqueId()));
}
public void saveMetadata(Player player, String id, Runnable after, JsonObject custom)
{
runAsync(() ->
{
JsonObject info = new JsonObject();
for (AnticheatMetadata anticheatMetadata : _metadata.values())
{
try
{
info.add(anticheatMetadata.getId(), anticheatMetadata.build(player.getUniqueId()));
}
catch (Throwable t)
{
t.printStackTrace();
}
}
info.add("custom", custom == null ? JsonNull.INSTANCE: custom);
String str = GSON.toJson(info);
byte[] b = str.getBytes(StandardCharsets.UTF_8);
ByteArrayOutputStream bout = new ByteArrayOutputStream();
try
{
XZOutputStream o2 = new XZOutputStream(bout, new LZMA2Options(LZMA2Options.PRESET_MIN), XZ.CHECK_NONE);
o2.write(b);
o2.close();
}
catch (IOException ex)
{
// Should never happen
ex.printStackTrace();
}
String base64 = Base64.getEncoder().encodeToString(bout.toByteArray());
_db.saveMetadata(_clientManager.getAccountId(player), id, base64, after);
});
}
public void registerMetadata(AnticheatMetadata metadata)
{
if (!this._metadata.containsKey(metadata.getId()))
{
this._metadata.put(metadata.getId(), metadata);
}
else
{
throw new IllegalArgumentException("Attempting to register: " + metadata.getId());
}
}
public void resetViolations(Player player, Runnable after)
{
_db.clearLastBan(_clientManager.getAccountId(player), after);
}
}

View File

@ -0,0 +1,55 @@
package mineplex.core.antihack.logging.builtin;
import java.util.UUID;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import mineplex.core.antihack.logging.AnticheatMetadata;
import mineplex.core.party.Party;
import mineplex.core.party.PartyManager;
import static mineplex.core.Managers.require;
public class PartyInfoMetadata extends AnticheatMetadata
{
private static final String KEY_OWNER = "owner";
private static final String KEY_MEMBERS = "members";
@Override
public String getId()
{
return "party-info";
}
@Override
public JsonElement build(UUID player)
{
Party party = require(PartyManager.class).getPlayerParties().get(player);
if (party != null)
{
JsonObject partyData = new JsonObject();
partyData.addProperty(KEY_OWNER, party.getOwner());
JsonArray members = new JsonArray();
party.getMembers().forEach(m -> members.add(new JsonPrimitive(m)));
partyData.add(KEY_MEMBERS, members);
return partyData;
}
else
{
return JsonNull.INSTANCE;
}
}
@Override
public void remove(UUID player)
{
}
}

View File

@ -0,0 +1,51 @@
package mineplex.core.antihack.logging.builtin;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import mineplex.core.account.CoreClientManager;
import mineplex.core.antihack.logging.AnticheatMetadata;
import static mineplex.core.Managers.require;
public class PlayerInfoMetadata extends AnticheatMetadata
{
private static final String KEY_UUID = "uuid";
private static final String KEY_ACCOUNT_ID = "accountid";
private static final String KEY_NAME = "name";
private final CoreClientManager _clientManager = require(CoreClientManager.class);
@Override
public String getId()
{
return "player-info";
}
@Override
public JsonElement build(UUID player)
{
JsonObject object = new JsonObject();
object.addProperty(KEY_UUID, player.toString());
Player bPlayer = Bukkit.getPlayer(player);
if (bPlayer != null)
{
object.addProperty(KEY_NAME, bPlayer.getName());
object.addProperty(KEY_ACCOUNT_ID, _clientManager.getAccountId(bPlayer));
}
return object;
}
@Override
public void remove(UUID player)
{
}
}

View File

@ -0,0 +1,38 @@
package mineplex.core.antihack.logging.builtin;
import java.util.UUID;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import mineplex.core.antihack.logging.AnticheatMetadata;
import mineplex.core.common.util.UtilServer;
public class ServerInfoMetadata extends AnticheatMetadata
{
private static final String KEY_SERVER_NAME = "server-name";
private static final String KEY_SERVER_REGION = "server-region";
private static final String KEY_SERVER_GROUP = "server-group";
@Override
public String getId()
{
return "server-info";
}
@Override
public JsonElement build(UUID player)
{
JsonObject info = new JsonObject();
info.addProperty(KEY_SERVER_NAME, UtilServer.getServerName());
info.addProperty(KEY_SERVER_REGION, UtilServer.getRegion().name());
info.addProperty(KEY_SERVER_GROUP, UtilServer.getGroup());
return info;
}
@Override
public void remove(UUID player)
{
}
}

View File

@ -0,0 +1,154 @@
package mineplex.core.antihack.logging.builtin;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import net.minecraft.server.v1_8_R3.MinecraftServer;
import org.bukkit.Location;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerJoinEvent;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.mineplex.anticheat.api.CheckDisabledEvent;
import com.mineplex.anticheat.api.PlayerViolationEvent;
import com.mineplex.anticheat.checks.Check;
import mineplex.core.antihack.logging.AnticheatMetadata;
import gnu.trove.map.TObjectIntMap;
import gnu.trove.map.TObjectLongMap;
import gnu.trove.map.hash.TObjectIntHashMap;
import gnu.trove.map.hash.TObjectLongHashMap;
public class ViolationInfoMetadata extends AnticheatMetadata
{
private static final Location MUTABLE_LOCATION = new Location(null, 0, 0, 0);
private static final String KEY_JOIN_TIME_MS = "join-time-ms";
private static final String KEY_JOIN_TIME_TICK = "join-time-tick";
private static final String KEY_CURRENT_TIME = "current-time";
private static final String KEY_MS = "ms";
private static final String KEY_TICK = "tick";
private static final String KEY_VIOLATION_INFO = "violation-info";
private static final String KEY_VL = "current-vl";
private static final String KEY_MESSAGE = "msg";
private static final String KEY_PLAYER_INFO = "player-info";
private static final String KEY_LOCATION = "loc";
private static final String KEY_WORLD = "world";
private static final String KEY_X = "x";
private static final String KEY_Y = "y";
private static final String KEY_Z = "z";
private static final String KEY_YAW = "yaw";
private static final String KEY_PITCH = "pitch";
private static final JsonObject VAL_CHECK_DISABLED;
static
{
VAL_CHECK_DISABLED = new JsonObject();
VAL_CHECK_DISABLED.addProperty(KEY_MESSAGE, "disabled");
}
private TObjectLongMap<UUID> _joinTime = new TObjectLongHashMap<>();
private TObjectIntMap<UUID> _joinTimeTick = new TObjectIntHashMap<>();
private Map<UUID, Map<Class<? extends Check>, List<JsonObject>>> _violations = new HashMap<>();
@Override
public String getId()
{
return "violation-info";
}
@Override
public JsonElement build(UUID player)
{
JsonObject object = new JsonObject();
object.addProperty(KEY_JOIN_TIME_MS, _joinTime.get(player));
object.addProperty(KEY_JOIN_TIME_TICK, _joinTimeTick.get(player));
_violations.get(player).forEach((check, list) ->
{
JsonArray checkElem = new JsonArray();
list.forEach(checkElem::add);
object.add(check.getName(), checkElem);
});
return object;
}
@Override
public void remove(UUID player)
{
_joinTime.remove(player);
_joinTimeTick.remove(player);
_violations.remove(player);
}
@EventHandler
public void onJoin(PlayerJoinEvent event)
{
long thisMs = System.currentTimeMillis();
int thisTick = MinecraftServer.getServer().at();
_joinTime.put(event.getPlayer().getUniqueId(), thisMs);
_joinTimeTick.put(event.getPlayer().getUniqueId(), thisTick);
_violations.put(event.getPlayer().getUniqueId(), new HashMap<>());
}
@EventHandler
public void onDisabledCheck(CheckDisabledEvent event)
{
_violations.values().forEach(map ->
{
List<JsonObject> data = map.get(event.getCheck());
if (data != null)
{
data.add(VAL_CHECK_DISABLED);
}
});
}
@EventHandler
public void onViolation(PlayerViolationEvent event)
{
long thisMs = System.currentTimeMillis();
int thisTick = MinecraftServer.getServer().at();
List<JsonObject> violations = _violations.get(event.getPlayer().getUniqueId()).computeIfAbsent(event.getCheckClass(), key -> new ArrayList<>());
JsonObject currentTime = new JsonObject();
currentTime.addProperty(KEY_MS, thisMs);
currentTime.addProperty(KEY_TICK, thisTick);
JsonObject violationInfo = new JsonObject();
violationInfo.addProperty(KEY_VL, event.getViolations());
violationInfo.addProperty(KEY_MESSAGE, event.getMessage());
event.getPlayer().getLocation(MUTABLE_LOCATION);
JsonObject playerInfo = new JsonObject();
JsonObject location = new JsonObject();
location.addProperty(KEY_WORLD, MUTABLE_LOCATION.getWorld().getName());
location.addProperty(KEY_X, MUTABLE_LOCATION.getX());
location.addProperty(KEY_Y, MUTABLE_LOCATION.getY());
location.addProperty(KEY_Z, MUTABLE_LOCATION.getZ());
location.addProperty(KEY_YAW, MUTABLE_LOCATION.getYaw());
location.addProperty(KEY_PITCH, MUTABLE_LOCATION.getPitch());
playerInfo.add(KEY_LOCATION, location);
JsonObject data = new JsonObject();
data.add(KEY_CURRENT_TIME, currentTime);
data.add(KEY_VIOLATION_INFO, violationInfo);
data.add(KEY_PLAYER_INFO, playerInfo);
violations.add(data);
}
}

View File

@ -0,0 +1,46 @@
package mineplex.core.antihack.redisnotifications;
import mineplex.serverdata.commands.ServerCommand;
public class GwenBanNotification extends ServerCommand
{
private final String _serverName;
private final String _playerName;
private final String _playerUUID;
private final String _hackType;
private final String _metadataId;
public GwenBanNotification(String serverName, String playerName, String playerUUID, String hackType, String metadataId)
{
_serverName = serverName;
_playerName = playerName;
_playerUUID = playerUUID;
_hackType = hackType;
_metadataId = metadataId;
}
public String getServerName()
{
return _serverName;
}
public String getPlayerName()
{
return _playerName;
}
public String getPlayerUUID()
{
return _playerUUID;
}
public String getHackType()
{
return _hackType;
}
public String getMetadataId()
{
return _metadataId;
}
}

View File

@ -0,0 +1,53 @@
package mineplex.core.antihack.redisnotifications;
import mineplex.serverdata.commands.ServerCommand;
public class GwenBanwaveNotification extends ServerCommand
{
private final String _serverName;
private final String _playerName;
private final String _playerUUID;
private final String _hackType;
private final String _metadataId;
private final long _timeToBan;
public GwenBanwaveNotification(String serverName, String playerName, String playerUUID, String hackType, String metadataId, long timeToBan)
{
_serverName = serverName;
_playerName = playerName;
_playerUUID = playerUUID;
_hackType = hackType;
_metadataId = metadataId;
_timeToBan = timeToBan;
}
public String getServerName()
{
return _serverName;
}
public String getPlayerName()
{
return _playerName;
}
public String getPlayerUUID()
{
return _playerUUID;
}
public String getHackType()
{
return _hackType;
}
public String getMetadataId()
{
return _metadataId;
}
public long getTimeToBan()
{
return _timeToBan;
}
}

View File

@ -1,172 +0,0 @@
package mineplex.core.antihack.types;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Map.Entry;
import mineplex.core.MiniPlugin;
import mineplex.core.antihack.AntiHack;
import mineplex.core.antihack.Detector;
import mineplex.core.common.util.UtilBlock;
import mineplex.core.common.util.UtilMath;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
public class Fly extends MiniPlugin implements Detector
{
private AntiHack Host;
private HashMap<Player, Entry<Integer, Double>> _floatTicks = new HashMap<Player, Entry<Integer, Double>>(); //Ticks, PrevY
private HashMap<Player, Entry<Integer, Double>> _hoverTicks = new HashMap<Player, Entry<Integer, Double>>(); //Ticks, PrevY
private HashMap<Player, Entry<Integer, Double>> _riseTicks = new HashMap<Player, Entry<Integer, Double>>(); //Ticks, PrevY
public Fly (AntiHack host)
{
super("Fly Detector", host.getPlugin());
Host = host;
}
@EventHandler(priority = EventPriority.MONITOR)
public void updateFlyhack(PlayerMoveEvent event)
{
if (!Host.isEnabled())
return;
Player player = event.getPlayer();
//100% Valid
if (Host.isValid(player, true))
Reset(player);
//Hasn't moved, just looking around
if (UtilMath.offset(event.getFrom(), event.getTo()) <= 0)
{
updateFloat(player);
return;
}
else
{
_floatTicks.remove(player);
}
updateHover(player);
updateRise(player);
}
private void updateFloat(Player player)
{
int count = 0;
if (_floatTicks.containsKey(player))
{
if (player.getLocation().getY() == _floatTicks.get(player).getValue())
{
count = _floatTicks.get(player).getKey() + 1;
}
else
{
count = 0;
}
}
if (count > Host.FloatHackTicks)
{
Host.addSuspicion(player, "Fly (Float)");
count -= 2;
}
_floatTicks.put(player, new AbstractMap.SimpleEntry<Integer, Double>(count, player.getLocation().getY()));
}
private void updateHover(Player player)
{
int count = 0;
if (_hoverTicks.containsKey(player))
{
if (player.getLocation().getY() == _hoverTicks.get(player).getValue())
{
count = _hoverTicks.get(player).getKey() + 1;
}
else
{
count = 0;
}
//player.sendMessage(count + " - " + player.getLocation().getY() + " vs " + _hoverTicks.get(player).getValue());
}
if (count > Host.HoverHackTicks)
{
Host.addSuspicion(player, "Fly (Hover)");
count -= 2;
}
_hoverTicks.put(player, new AbstractMap.SimpleEntry<Integer, Double>(count, player.getLocation().getY()));
}
private void updateRise(Player player)
{
int count = 0;
if (_riseTicks.containsKey(player))
{
if (player.getLocation().getY() >= _riseTicks.get(player).getValue())
{
boolean nearBlocks = false;
for (Block block : UtilBlock.getSurrounding(player.getLocation().getBlock(), true))
{
if (block.getType() != Material.AIR)
{
nearBlocks = true;
break;
}
}
for (PotionEffect effect : player.getActivePotionEffects())
if (effect.getType() == PotionEffectType.JUMP || effect.getType().equals(PotionEffectType.JUMP))
nearBlocks = true;
if (nearBlocks)
{
count = 0;
}
else
{
count = _riseTicks.get(player).getKey() + 1;
}
}
else
{
count = 0;
}
}
if (count > Host.RiseHackTicks)
{
//Only give Offense if actually rising - initial ticks can be trigged via Hover.
if (player.getLocation().getY() > _riseTicks.get(player).getValue())
Host.addSuspicion(player, "Fly (Rise)");
count -= 2;
}
_riseTicks.put(player, new AbstractMap.SimpleEntry<Integer, Double>(count, player.getLocation().getY()));
}
@Override
public void Reset(Player player)
{
_floatTicks.remove(player);
_hoverTicks.remove(player);
_riseTicks.remove(player);
}
}

View File

@ -1,78 +0,0 @@
package mineplex.core.antihack.types;
import java.util.HashMap;
import mineplex.core.MiniPlugin;
import mineplex.core.antihack.AntiHack;
import mineplex.core.antihack.Detector;
import mineplex.core.common.util.C;
import mineplex.core.common.util.UtilPlayer;
import mineplex.core.common.util.UtilServer;
import mineplex.core.common.util.UtilTime;
import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerMoveEvent;
public class Idle extends MiniPlugin implements Detector
{
private AntiHack Host;
private HashMap<Player, Long> _idleTime = new HashMap<Player, Long>();
public Idle (AntiHack host)
{
super("Idle Detector", host.getPlugin());
Host = host;
}
@EventHandler(priority = EventPriority.MONITOR)
public void updateFlyhack(PlayerMoveEvent event)
{
if (!Host.isEnabled())
return;
Player player = event.getPlayer();
_idleTime.put(player, System.currentTimeMillis());
}
@EventHandler(priority = EventPriority.MONITOR)
public void updateFreeCam(UpdateEvent event)
{
if (!Host.isEnabled())
return;
if (event.getType() != UpdateType.FAST)
return;
for (Player player : UtilServer.getPlayers())
{
//100% Valid
if (Host.isValid(player, true))
continue;
if (!_idleTime.containsKey(player))
continue;
if (!UtilTime.elapsed(_idleTime.get(player), Host.IdleTime))
continue;
//Host.addSuspicion(player, "Lag / Fly (Idle)");
//player.kickPlayer(C.cGold + "Mineplex " + C.cRed + "Anti-Cheat " + C.cWhite + "Kicked for Lag / Fly (Idle)");
UtilPlayer.message(player, C.cRed + C.Bold + "Mineplex Anti-Cheat detected Lagging / Fly (Idle)");
UtilPlayer.message(player, C.cRed + C.Bold + "You have been returned to Lobby.");
Host.Portal.sendPlayerToServer(player, "Lobby");
}
}
@Override
public void Reset(Player player)
{
_idleTime.remove(player);
}
}

View File

@ -1,123 +0,0 @@
package mineplex.core.antihack.types;
import java.util.ArrayList;
import java.util.HashMap;
import mineplex.core.MiniPlugin;
import mineplex.core.antihack.AntiHack;
import mineplex.core.antihack.Detector;
import mineplex.core.common.util.UtilEvent;
import mineplex.core.common.util.UtilMath;
import mineplex.core.common.util.UtilPlayer;
import mineplex.core.common.util.UtilServer;
import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
public class Reach extends MiniPlugin implements Detector
{
private AntiHack Host;
private HashMap<Player, ArrayList<Location>> _history = new HashMap<Player, ArrayList<Location>>();
public Reach (AntiHack host)
{
super("Reach Detector", host.getPlugin());
Host = host;
}
@EventHandler(priority = EventPriority.LOWEST)
public void recordMove(UpdateEvent event)
{
if (!Host.isEnabled())
return;
if (event.getType() != UpdateType.TICK)
return;
for (Player player : UtilServer.getPlayers())
{
if (player.getGameMode() != GameMode.SURVIVAL || UtilPlayer.isSpectator(player))
continue;
if (!_history.containsKey(player))
_history.put(player, new ArrayList<Location>());
_history.get(player).add(0, player.getLocation());
while (_history.get(player).size() > 40)
{
_history.get(player).remove(_history.get(player).size()-1);
}
}
}
@EventHandler(priority = EventPriority.LOWEST)
public void reachDetect(EntityDamageEvent event)
{
if (event.getCause() != DamageCause.ENTITY_ATTACK)
return;
if (!(event.getEntity() instanceof Player))
return;
LivingEntity damagerEntity = UtilEvent.GetDamagerEntity(event, false);
if (!(damagerEntity instanceof Player))
return;
Player damager = (Player)damagerEntity;
Player damagee = (Player)event.getEntity();
if (!isInRange(damager.getLocation(), damagee.getLocation()))
{
ArrayList<Location> damageeHistory = _history.get(damagee);
if (damageeHistory != null)
{
for (Location historyLoc : damageeHistory)
{
if (isInRange(damager.getLocation(), historyLoc))
{
return;
}
}
}
//Host.addSuspicion(damager, "Reach");
}
}
private boolean isInRange(Location a, Location b)
{
//2d Range
double distFlat = UtilMath.offset2d(a, b); //Limit is 3.40
if (distFlat > 3.4)
{
return true;
}
//3d Range
double dist = UtilMath.offset(a, b); //Limit is 6 (highest i saw was 5.67)
if (dist > 6.0)
{
return true;
}
return false;
}
@Override
public void Reset(Player player)
{
_history.remove(player);
}
}

View File

@ -1,105 +0,0 @@
package mineplex.core.antihack.types;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Map.Entry;
import mineplex.core.MiniPlugin;
import mineplex.core.antihack.AntiHack;
import mineplex.core.antihack.Detector;
import mineplex.core.common.util.UtilEnt;
import mineplex.core.common.util.UtilMath;
import mineplex.core.common.util.UtilTime;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
public class Speed extends MiniPlugin implements Detector
{
private AntiHack Host;
private HashMap<Player, Entry<Integer, Long>> _speedTicks = new HashMap<Player, Entry<Integer, Long>>(); //Ticks, PrevY
public Speed (AntiHack host)
{
super("Speed Detector", host.getPlugin());
Host = host;
}
@EventHandler(priority = EventPriority.MONITOR)
public void updateSpeedhack(PlayerMoveEvent event)
{
if (!Host.isEnabled())
return;
Player player = event.getPlayer();
//100% Valid
if (Host.isValid(player, false))
return;
UpdateSpeed(player, event);
}
private void UpdateSpeed(Player player, PlayerMoveEvent event)
{
int count = 0;
if (_speedTicks.containsKey(player))
{
double offset;
if (event.getFrom().getY() > event.getTo().getY())
{
offset = UtilMath.offset2d(event.getFrom(), event.getTo());
}
else
{
offset = UtilMath.offset(event.getFrom(), event.getTo());
}
//Limit
double limit = 0.74;
if (UtilEnt.isGrounded(player))
limit = 0.32;
for (PotionEffect effect : player.getActivePotionEffects())
{
if (effect.getType().equals(PotionEffectType.SPEED))
{
if (UtilEnt.isGrounded(player))
limit += 0.08 * (effect.getAmplifier() + 1);
else
limit += 0.04 * (effect.getAmplifier() + 1);
}
}
//Check
if (offset > limit && !UtilTime.elapsed(_speedTicks.get(player).getValue(), 100))//Counters Lag
{
count = _speedTicks.get(player).getKey() + 1;
}
else
{
count = 0;
}
}
if (count > Host.SpeedHackTicks)
{
Host.addSuspicion(player, "Speed (Fly/Move)");
count -= 2;
}
_speedTicks.put(player, new AbstractMap.SimpleEntry<Integer, Long>(count, System.currentTimeMillis()));
}
@Override
public void Reset(Player player)
{
_speedTicks.remove(player);
}
}

View File

@ -1,6 +1,7 @@
package mineplex.core.punish; package mineplex.core.punish;
import java.util.HashMap; import java.util.HashMap;
import java.util.function.Consumer;
import java.util.logging.Level; import java.util.logging.Level;
import mineplex.core.account.CoreClient; import mineplex.core.account.CoreClient;
@ -167,6 +168,11 @@ public class Punish extends MiniPlugin
} }
public void AddPunishment(String playerName, final Category category, final String reason, String callerName, final int severity, boolean ban, long duration, final boolean silent) public void AddPunishment(String playerName, final Category category, final String reason, String callerName, final int severity, boolean ban, long duration, final boolean silent)
{
AddPunishment(playerName, category, reason, callerName, severity, ban, duration, silent, null);
}
public void AddPunishment(String playerName, final Category category, final String reason, String callerName, final int severity, boolean ban, long duration, final boolean silent, Consumer<PunishmentResponse> callback)
{ {
Player player = Bukkit.getPlayerExact(playerName); Player player = Bukkit.getPlayerExact(playerName);
if (player != null) if (player != null)
@ -250,7 +256,7 @@ public class Punish extends MiniPlugin
if (player != null) if (player != null)
player.kickPlayer(kickReason); player.kickPlayer(kickReason);
else
new mineplex.serverdata.commands.PunishCommand(finalPlayerName, true, false, kickReason).publish(); new mineplex.serverdata.commands.PunishCommand(finalPlayerName, true, false, kickReason).publish();
} }
}); });
@ -277,7 +283,7 @@ public class Punish extends MiniPlugin
UtilPlayer.message(player, F.main("Punish", F.elem(C.cGray + C.Bold + "Reason: ") + reason)); UtilPlayer.message(player, F.main("Punish", F.elem(C.cGray + C.Bold + "Reason: ") + reason));
player.playSound(player.getLocation(), Sound.CAT_MEOW, 1f, 1f); player.playSound(player.getLocation(), Sound.CAT_MEOW, 1f, 1f);
} }
else
new mineplex.serverdata.commands.PunishCommand(finalPlayerName, false, finalDuration != 0, F.main("Punish", F.elem(C.cGray + C.Bold + "Report Ban Reason: ") + reason)).publish(); new mineplex.serverdata.commands.PunishCommand(finalPlayerName, false, finalDuration != 0, F.main("Punish", F.elem(C.cGray + C.Bold + "Report Ban Reason: ") + reason)).publish();
_repository.LoadPunishClient(finalPlayerName, new Callback<PunishClientToken>() _repository.LoadPunishClient(finalPlayerName, new Callback<PunishClientToken>()
@ -316,7 +322,7 @@ public class Punish extends MiniPlugin
UtilPlayer.message(player, F.main("Punish", F.elem(C.cGray + C.Bold + "Reason: ") + reason)); UtilPlayer.message(player, F.main("Punish", F.elem(C.cGray + C.Bold + "Reason: ") + reason));
player.playSound(player.getLocation(), Sound.CAT_MEOW, 1f, 1f); player.playSound(player.getLocation(), Sound.CAT_MEOW, 1f, 1f);
} }
else
new mineplex.serverdata.commands.PunishCommand(finalPlayerName, false, finalDuration != 0, F.main("Punish", F.elem(C.cGray + C.Bold + (finalDuration != 0 ? "Mute" : "Warning") + " Reason: ") + reason)).publish(); new mineplex.serverdata.commands.PunishCommand(finalPlayerName, false, finalDuration != 0, F.main("Punish", F.elem(C.cGray + C.Bold + (finalDuration != 0 ? "Mute" : "Warning") + " Reason: ") + reason)).publish();
_repository.LoadPunishClient(finalPlayerName, new Callback<PunishClientToken>() _repository.LoadPunishClient(finalPlayerName, new Callback<PunishClientToken>()
@ -328,6 +334,10 @@ public class Punish extends MiniPlugin
}); });
} }
} }
if (callback != null)
{
callback.accept(banResult);
}
} }

View File

@ -259,15 +259,6 @@ public class PunishPage extends CraftInventoryCustom implements Listener
int flightSeverity = 2; int flightSeverity = 2;
try
{
if (Managers.get(AntiHack.class).isStrict())
{
flightSeverity = 3;
}
}
catch (Exception e) {}
AddButton(41, new ShopItem(Material.INK_SACK, (byte)1, "Severity 3",new String[] AddButton(41, new ShopItem(Material.INK_SACK, (byte)1, "Severity 3",new String[]
{ {

View File

@ -6,7 +6,8 @@ import mineplex.core.TimingsFix;
import mineplex.core.account.CoreClientManager; import mineplex.core.account.CoreClientManager;
import mineplex.core.achievement.AchievementManager; import mineplex.core.achievement.AchievementManager;
import mineplex.core.antihack.AntiHack; import mineplex.core.antihack.AntiHack;
import mineplex.core.antihack.AntiHackGuardian; import mineplex.core.antihack.guardians.AntiHackGuardian;
import mineplex.core.antihack.guardians.GuardianManager;
import mineplex.core.blockrestore.BlockRestore; import mineplex.core.blockrestore.BlockRestore;
import mineplex.core.chat.Chat; import mineplex.core.chat.Chat;
import mineplex.core.chatsnap.SnapshotManager; import mineplex.core.chatsnap.SnapshotManager;
@ -139,8 +140,9 @@ public class Clans extends JavaPlugin
Creature creature = new Creature(this); Creature creature = new Creature(this);
AntiHack antiHack = require(AntiHack.class); AntiHack antiHack = require(AntiHack.class);
antiHack.setKick(false); GuardianManager guardianManager = require(GuardianManager.class);
Bukkit.getScheduler().runTask(this, antiHack::enableNewAnticheat);
Bukkit.getScheduler().runTask(this, antiHack::enableAnticheat);
new EternalGiveawayManager(this, _clientManager, serverStatusManager); new EternalGiveawayManager(this, _clientManager, serverStatusManager);
@ -155,7 +157,7 @@ public class Clans extends JavaPlugin
Location spawn = new Location(Bukkit.getWorld("world"), -422, 95, 8); Location spawn = new Location(Bukkit.getWorld("world"), -422, 95, 8);
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
{ {
antiHack.registerGuardian(new AntiHackGuardian(spawn.clone(), maxX, minX, maxY, minY, maxZ, minZ)); guardianManager.registerGuardian(new AntiHackGuardian(spawn.clone(), maxX, minX, maxY, minY, maxZ, minZ));
} }
} }
@ -170,7 +172,7 @@ public class Clans extends JavaPlugin
Location spawn = new Location(Bukkit.getWorld("world"), 424, 95, -8); Location spawn = new Location(Bukkit.getWorld("world"), 424, 95, -8);
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
{ {
antiHack.registerGuardian(new AntiHackGuardian(spawn.clone(), maxX, minX, maxY, minY, maxZ, minZ)); guardianManager.registerGuardian(new AntiHackGuardian(spawn.clone(), maxX, minX, maxY, minY, maxZ, minZ));
} }
} }
@ -185,7 +187,7 @@ public class Clans extends JavaPlugin
Location spawn = new Location(Bukkit.getWorld("world"), 9, 210, -393); Location spawn = new Location(Bukkit.getWorld("world"), 9, 210, -393);
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
{ {
antiHack.registerGuardian(new AntiHackGuardian(spawn.clone(), maxX, minX, maxY, minY, maxZ, minZ)); guardianManager.registerGuardian(new AntiHackGuardian(spawn.clone(), maxX, minX, maxY, minY, maxZ, minZ));
} }
} }
@ -200,7 +202,7 @@ public class Clans extends JavaPlugin
Location spawn = new Location(Bukkit.getWorld("world"), 8, 210, 390); Location spawn = new Location(Bukkit.getWorld("world"), 8, 210, 390);
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
{ {
antiHack.registerGuardian(new AntiHackGuardian(spawn.clone(), maxX, minX, maxY, minY, maxZ, minZ)); guardianManager.registerGuardian(new AntiHackGuardian(spawn.clone(), maxX, minX, maxY, minY, maxZ, minZ));
} }
} }
@ -215,7 +217,7 @@ public class Clans extends JavaPlugin
Location spawn = new Location(Bukkit.getWorld("world"), 0, 100, 0); Location spawn = new Location(Bukkit.getWorld("world"), 0, 100, 0);
for (int i = 0; i < 40; i++) for (int i = 0; i < 40; i++)
{ {
antiHack.registerGuardian(new AntiHackGuardian(spawn.clone(), maxX, minX, maxY, minY, maxZ, minZ)); guardianManager.registerGuardian(new AntiHackGuardian(spawn.clone(), maxX, minX, maxY, minY, maxZ, minZ));
} }
} }

View File

@ -5,7 +5,8 @@ import mineplex.core.PacketsInteractionFix;
import mineplex.core.account.CoreClientManager; import mineplex.core.account.CoreClientManager;
import mineplex.core.achievement.AchievementManager; import mineplex.core.achievement.AchievementManager;
import mineplex.core.antihack.AntiHack; import mineplex.core.antihack.AntiHack;
import mineplex.core.antihack.AntiHackGuardian; import mineplex.core.antihack.guardians.AntiHackGuardian;
import mineplex.core.antihack.guardians.GuardianManager;
import mineplex.core.aprilfools.AprilFoolsManager; import mineplex.core.aprilfools.AprilFoolsManager;
import mineplex.core.blockrestore.BlockRestore; import mineplex.core.blockrestore.BlockRestore;
import mineplex.core.boosters.BoosterManager; import mineplex.core.boosters.BoosterManager;
@ -120,10 +121,11 @@ public class ClansHub extends JavaPlugin
Portal portal = new Portal(this, clientManager, serverStatusManager.getCurrentServerName()); Portal portal = new Portal(this, clientManager, serverStatusManager.getCurrentServerName());
AntiHack antiHack = require(AntiHack.class); AntiHack antiHack = require(AntiHack.class);
GuardianManager guardianManager = require(GuardianManager.class);
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
antiHack.registerGuardian(new AntiHackGuardian(new Location(Bukkit.getWorld("world"), 0, 195, 0), 25, -8, 195, 185, 17, -16)); guardianManager.registerGuardian(new AntiHackGuardian(new Location(Bukkit.getWorld("world"), 0, 195, 0), 25, -8, 195, 185, 17, -16));
} }
IgnoreManager ignoreManager = new IgnoreManager(this, clientManager, preferenceManager, portal); IgnoreManager ignoreManager = new IgnoreManager(this, clientManager, preferenceManager, portal);

View File

@ -10,7 +10,8 @@ import mineplex.core.PacketsInteractionFix;
import mineplex.core.account.CoreClientManager; import mineplex.core.account.CoreClientManager;
import mineplex.core.achievement.AchievementManager; import mineplex.core.achievement.AchievementManager;
import mineplex.core.antihack.AntiHack; import mineplex.core.antihack.AntiHack;
import mineplex.core.antihack.AntiHackGuardian; import mineplex.core.antihack.guardians.AntiHackGuardian;
import mineplex.core.antihack.guardians.GuardianManager;
import mineplex.core.aprilfools.AprilFoolsManager; import mineplex.core.aprilfools.AprilFoolsManager;
import mineplex.core.blockrestore.BlockRestore; import mineplex.core.blockrestore.BlockRestore;
import mineplex.core.boosters.BoosterManager; import mineplex.core.boosters.BoosterManager;
@ -147,10 +148,11 @@ public class Hub extends JavaPlugin implements IRelation
Portal portal = new Portal(this, clientManager, serverStatusManager.getCurrentServerName()); Portal portal = new Portal(this, clientManager, serverStatusManager.getCurrentServerName());
AntiHack antiHack = require(AntiHack.class); AntiHack antiHack = require(AntiHack.class);
GuardianManager guardianManager = require(GuardianManager.class);
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
antiHack.registerGuardian(new AntiHackGuardian(new Location(Bukkit.getWorld("world"), 0, 100, 0), 50, -50, 105, 95, 50, -50)); guardianManager.registerGuardian(new AntiHackGuardian(new Location(Bukkit.getWorld("world"), 0, 100, 0), 50, -50, 105, 95, 50, -50));
} }
IgnoreManager ignoreManager = new IgnoreManager(this, clientManager, preferenceManager, portal); IgnoreManager ignoreManager = new IgnoreManager(this, clientManager, preferenceManager, portal);

View File

@ -4,6 +4,7 @@ import mineplex.core.CustomTagFix;
import mineplex.core.FoodDupeFix; import mineplex.core.FoodDupeFix;
import mineplex.core.PacketsInteractionFix; import mineplex.core.PacketsInteractionFix;
import mineplex.core.TimingsFix; import mineplex.core.TimingsFix;
import mineplex.core.antihack.logging.AntihackLogger;
import mineplex.core.chatsnap.SnapshotRepository; import mineplex.core.chatsnap.SnapshotRepository;
import mineplex.core.customdata.CustomDataManager; import mineplex.core.customdata.CustomDataManager;
import mineplex.core.chatsnap.SnapshotManager; import mineplex.core.chatsnap.SnapshotManager;
@ -65,6 +66,8 @@ import mineplex.core.velocity.VelocityFix;
import mineplex.core.visibility.VisibilityManager; import mineplex.core.visibility.VisibilityManager;
import mineplex.minecraft.game.core.combat.CombatManager; import mineplex.minecraft.game.core.combat.CombatManager;
import mineplex.minecraft.game.core.damage.DamageManager; import mineplex.minecraft.game.core.damage.DamageManager;
import nautilus.game.arcade.anticheatmetadata.GameInfoMetadata;
import nautilus.game.arcade.game.GameServerConfig; import nautilus.game.arcade.game.GameServerConfig;
import net.minecraft.server.v1_8_R3.BiomeBase; import net.minecraft.server.v1_8_R3.BiomeBase;
import net.minecraft.server.v1_8_R3.MinecraftServer; import net.minecraft.server.v1_8_R3.MinecraftServer;
@ -149,8 +152,7 @@ public class Arcade extends JavaPlugin
Punish punish = new Punish(this, webServerAddress, _clientManager); Punish punish = new Punish(this, webServerAddress, _clientManager);
AntiHack antiHack = require(AntiHack.class); require(AntiHack.class);
antiHack.setKick(false);
IgnoreManager ignoreManager = new IgnoreManager(this, _clientManager, preferenceManager, portal); IgnoreManager ignoreManager = new IgnoreManager(this, _clientManager, preferenceManager, portal);
StatsManager statsManager = new StatsManager(this, _clientManager); StatsManager statsManager = new StatsManager(this, _clientManager);
@ -187,6 +189,8 @@ public class Arcade extends JavaPlugin
PollManager pollManager = new PollManager(this, _clientManager, _donationManager); PollManager pollManager = new PollManager(this, _clientManager, _donationManager);
_gameManager = new ArcadeManager(this, serverStatusManager, ReadServerConfig(), _clientManager, _donationManager, _damageManager, statsManager, incognito, achievementManager, disguiseManager, creature, teleport, new Blood(this), chat, portal, preferenceManager, inventoryManager, packetHandler, cosmeticManager, projectileManager, petManager, hologramManager, webServerAddress, pollManager, npcmanager, customDataManager, punish, eloManager, thankManager, boosterManager); _gameManager = new ArcadeManager(this, serverStatusManager, ReadServerConfig(), _clientManager, _donationManager, _damageManager, statsManager, incognito, achievementManager, disguiseManager, creature, teleport, new Blood(this), chat, portal, preferenceManager, inventoryManager, packetHandler, cosmeticManager, projectileManager, petManager, hologramManager, webServerAddress, pollManager, npcmanager, customDataManager, punish, eloManager, thankManager, boosterManager);
require(AntihackLogger.class).registerMetadata(new GameInfoMetadata());
new GlobalPacketManager(this, _clientManager, serverStatusManager, inventoryManager, _donationManager, petManager, statsManager, _gameManager.getBonusManager().getRewardManager()); new GlobalPacketManager(this, _clientManager, serverStatusManager, inventoryManager, _donationManager, petManager, statsManager, _gameManager.getBonusManager().getRewardManager());
//new BroadcastManager(this, _gameManager); //new BroadcastManager(this, _gameManager);

View File

@ -0,0 +1,207 @@
package nautilus.game.arcade.anticheatmetadata;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerJoinEvent;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import mineplex.core.antihack.logging.AnticheatMetadata;
import mineplex.core.common.util.UtilServer;
import nautilus.game.arcade.ArcadeManager;
import nautilus.game.arcade.events.GameStateChangeEvent;
import nautilus.game.arcade.game.Game;
import nautilus.game.arcade.kit.Kit;
import nautilus.game.arcade.kit.ProgressingKit;
import nautilus.game.arcade.managers.GameHostManager;
import static mineplex.core.Managers.require;
public class GameInfoMetadata extends AnticheatMetadata
{
private static final String KEY_GAME_INFO = "game-info";
private static final String KEY_GAME_MAP = "map";
private static final String KEY_GAME_TYPE = "type";
private static final String KEY_GAME_MODE = "mode";
private static final String KEY_CURRENT_STATE = "current-state";
private static final String KEY_STATE_START_TIME = "current-state-start-time";
private static final String KEY_JOIN_GAME_TIME = "join-game-time-ms";
private static final String KEY_STATE_TIMES = "state-times";
private static final String KEY_KIT_INFO = "kit-info";
private static final String KEY_KIT_NAME = "name";
private static final String KEY_KIT_LEVEL = "level";
private static final String KEY_MPS = "mps";
private static final String KEY_OWNER = "owner";
private static final String KEY_STATS = "stats";
private static final String KEY_WINNER = "winner";
private final Map<UUID, JsonArray> _allGames = new HashMap<>();
private final Map<UUID, JsonObject> _currentGame = new HashMap<>();
private final ArcadeManager _arcadeManager = require(ArcadeManager.class);
@Override
public String getId()
{
return "game-info";
}
@EventHandler
public void onJoin(PlayerJoinEvent event)
{
_allGames.put(event.getPlayer().getUniqueId(), new JsonArray());
JsonObject currentGame = buildCurrentGame();
if (currentGame != null)
{
_currentGame.put(event.getPlayer().getUniqueId(), currentGame);
}
}
private JsonObject buildCurrentGame()
{
Game game = _arcadeManager.GetGame();
if (game == null)
return null;
JsonObject currentGame = new JsonObject();
JsonObject gameInfo = new JsonObject();
gameInfo.addProperty(KEY_GAME_MAP, game.WorldData.File);
gameInfo.addProperty(KEY_GAME_TYPE, game.GetName());
gameInfo.addProperty(KEY_GAME_MODE, game.GetMode());
gameInfo.addProperty(KEY_CURRENT_STATE, game.GetState().name());
gameInfo.addProperty(KEY_STATE_START_TIME, game.GetStateTime());
gameInfo.addProperty(KEY_JOIN_GAME_TIME, System.currentTimeMillis());
if (_arcadeManager.GetGameHostManager() != null && _arcadeManager.GetGameHostManager().isPrivateServer())
{
GameHostManager gameHostManager = _arcadeManager.GetGameHostManager();
JsonObject mpsInfo = new JsonObject();
mpsInfo.addProperty(KEY_OWNER, _arcadeManager.GetHost());
currentGame.add(KEY_MPS, mpsInfo);
}
currentGame.add(KEY_GAME_INFO, gameInfo);
JsonObject stateStartTimes = new JsonObject();
stateStartTimes.addProperty(game.GetState().name(), game.GetStateTime());
currentGame.add(KEY_STATE_TIMES, stateStartTimes);
return currentGame;
}
@EventHandler
public void onStateChange(GameStateChangeEvent event)
{
if (event.GetState() == Game.GameState.Recruit)
{
for (Player player : UtilServer.getPlayersCollection())
{
if (!_currentGame.containsKey(player.getUniqueId()))
{
_currentGame.put(player.getUniqueId(), buildCurrentGame());
}
}
}
if (event.GetState() == Game.GameState.Live)
{
_currentGame.forEach((id, obj) ->
{
Player player = Bukkit.getPlayer(id);
if (player != null)
{
Kit kit = event.GetGame().GetKit(player);
if (kit != null)
{
JsonObject kitInfo = new JsonObject();
kitInfo.addProperty(KEY_KIT_NAME, kit.GetName());
if (kit instanceof ProgressingKit)
{
ProgressingKit pk = (ProgressingKit) kit;
kitInfo.addProperty(KEY_KIT_LEVEL, pk.getLevel(player.getUniqueId()));
}
obj.add(KEY_KIT_INFO, kitInfo);
}
}
});
}
_currentGame.values().forEach(obj ->
{
obj.get(KEY_STATE_TIMES).getAsJsonObject().addProperty(event.GetState().name(), System.currentTimeMillis());
});
if (event.GetState() == Game.GameState.Dead)
{
new ArrayList<>(_currentGame.keySet()).forEach(ent -> archivePlayer(event.GetGame(), ent));
}
}
private void archivePlayer(Game game, UUID uuid)
{
JsonObject gameObj = _currentGame.remove(uuid);
if (gameObj == null)
return;
_allGames.get(uuid).add(gameObj);
if (game == null)
return;
Player player = Bukkit.getPlayer(uuid);
if (player == null)
return;
Map<String, Integer> stats = game.GetStats().get(player);
if (stats != null)
{
JsonObject statsObject = new JsonObject();
stats.forEach(statsObject::addProperty);
gameObj.add(KEY_STATS, statsObject);
}
gameObj.addProperty(KEY_WINNER, game.Winner);
}
@Override
public JsonElement build(UUID player)
{
archivePlayer(_arcadeManager.GetGame(), player);
return _allGames.get(player);
}
@Override
public void remove(UUID player)
{
_allGames.remove(player);
_currentGame.remove(player);
}
}

View File

@ -82,6 +82,9 @@ import nautilus.game.arcade.events.GameStateChangeEvent;
import nautilus.game.arcade.events.PlayerGameRespawnEvent; import nautilus.game.arcade.events.PlayerGameRespawnEvent;
import nautilus.game.arcade.events.PlayerStateChangeEvent; import nautilus.game.arcade.events.PlayerStateChangeEvent;
import nautilus.game.arcade.game.GameTeam.PlayerState; import nautilus.game.arcade.game.GameTeam.PlayerState;
import nautilus.game.arcade.game.games.build.Build;
import nautilus.game.arcade.game.games.draw.Draw;
import nautilus.game.arcade.game.games.speedbuilders.SpeedBuilders;
import nautilus.game.arcade.game.modules.Module; import nautilus.game.arcade.game.modules.Module;
import nautilus.game.arcade.kit.ChampionsKit; import nautilus.game.arcade.kit.ChampionsKit;
import nautilus.game.arcade.kit.Kit; import nautilus.game.arcade.kit.Kit;
@ -740,11 +743,14 @@ public abstract class Game implements Listener
if (this._gameState == Game.GameState.Prepare) if (this._gameState == Game.GameState.Prepare)
{ {
Managers.get(AntiHack.class).enableNewAnticheat(); if (!(this instanceof SpeedBuilders) && !(this instanceof Build) && !(this instanceof Draw))
{
Managers.get(AntiHack.class).enableAnticheat();
}
} }
else if (this._gameState == Game.GameState.End) else if (this._gameState == Game.GameState.End)
{ {
Managers.get(AntiHack.class).disableNewAnticheat(); Managers.get(AntiHack.class).disableAnticheat();
} }

View File

@ -1231,16 +1231,6 @@ public class GameFlagManager implements Listener
} }
} }
@EventHandler
public void AntiHackStrict(GameStateChangeEvent event)
{
if (event.GetState() == GameState.Prepare || event.GetState() == GameState.Live)
Managers.get(AntiHack.class).setStrict(event.GetGame().StrictAntiHack);
else
Managers.get(AntiHack.class).setStrict(true);
}
@EventHandler @EventHandler
public void PlayerKillCommandCancel(PlayerCommandPreprocessEvent event) public void PlayerKillCommandCancel(PlayerCommandPreprocessEvent event)
{ {