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>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>com.mineplex</groupId>
<artifactId>mineplex-serverdata</artifactId>
<version>dev-SNAPSHOT</version>
</dependency>
</dependencies>
<build>

View File

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

View File

@ -1,7 +1,10 @@
package mineplex.core.common.util;
import com.google.common.collect.Lists;
import mineplex.core.common.events.PlayerRecieveBroadcastEvent;
import mineplex.serverdata.Region;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.Sound;
@ -13,6 +16,7 @@ import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;
import java.lang.reflect.Field;
import java.util.*;
@ -135,6 +139,16 @@ public class UtilServer
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()
{
return getPlugin().getConfig().getString("serverstatus.group").equalsIgnoreCase("Testing");
@ -180,4 +194,39 @@ public class UtilServer
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>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.tukaani</groupId>
<artifactId>xz</artifactId>
<version>1.5</version>
</dependency>
</dependencies>
<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;
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.ChatModifier;
import net.minecraft.server.v1_8_R3.EnumChatFormat;
@ -25,10 +27,9 @@ public class CheckThresholds
return _friendlyName;
}
public IChatBaseComponent format(int violationLevel)
public void format(ComponentBuilder builder, int violationLevel)
{
EnumChatFormat color = getSeverity(violationLevel)._color;
return new ChatComponentText(_friendlyName).setChatModifier(new ChatModifier().setColor(color));
builder.append(_friendlyName, ComponentBuilder.FormatRetention.NONE).color(getSeverity(violationLevel)._color);
}
public Severity getSeverity(int violationLevel)
@ -51,14 +52,14 @@ public class CheckThresholds
public enum Severity
{
NONE(EnumChatFormat.GREEN),
LOW(EnumChatFormat.GREEN),
MEDIUM(EnumChatFormat.GOLD),
HIGH(EnumChatFormat.RED),
NONE(ChatColor.GREEN),
LOW(ChatColor.GREEN),
MEDIUM(ChatColor.GOLD),
HIGH(ChatColor.RED),
;
private final EnumChatFormat _color;
private final ChatColor _color;
Severity(EnumChatFormat color)
Severity(ChatColor 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.KillauraTypeD;
import com.mineplex.anticheat.checks.move.Glide;
import com.mineplex.anticheat.checks.move.HeadRoll;
import com.mineplex.anticheat.checks.move.Speed;
import mineplex.core.common.util.UtilServer;
import org.bukkit.event.Listener;
@ -13,40 +14,19 @@ import java.util.HashMap;
import java.util.Map;
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 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;
private final int _vl;
AntiHackAction(int vl)
{
this._vl = vl;
UtilServer.RegisterEvents(this);
}
public abstract void handle(PlayerViolationEvent event);
public int getMinVl()
public final int getMinVl()
{
return this._vl;
}
public static AntiHackAction getAction(Class<?> checkClass)
{
AntiHackAction action = ACTIONS.getOrDefault(checkClass, NOOP_ACTION);
return action;
}
public abstract void handle(PlayerViolationEvent event);
}

View File

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

View File

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

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

View File

@ -5,14 +5,25 @@ import mineplex.core.ReflectivelyCreateMiniPlugin;
import mineplex.core.account.CoreClient;
import mineplex.core.account.CoreClientManager;
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.event.EventHandler;
import org.bukkit.event.player.PlayerJoinEvent;
import com.google.gson.JsonObject;
import com.mineplex.anticheat.checks.Check;
import com.mineplex.anticheat.checks.CheckManager;
@ReflectivelyCreateMiniPlugin
public class BanWaveManager extends MiniPlugin
{
private final BanWaveRepository _repository = new BanWaveRepository();
private final CoreClientManager _clientManager = require(CoreClientManager.class);
private BanWaveManager()
{
@ -32,29 +43,39 @@ public class BanWaveManager extends MiniPlugin
if (info.getTimeToBan() < now)
{
require(AntiHack.class).doBanWave(event.getPlayer(), info.getMessage());
require(AntiHack.class).doBanWave(event.getPlayer(), 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(() ->
{
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), " +
"vl INT, " +
"server VARCHAR(32), " +
"metadata VARCHAR(10), " +
"PRIMARY KEY (accountId)," +
"FOREIGN KEY (accountId) REFERENCES accounts(id))";
@ -28,12 +29,14 @@ public class BanWaveRepository extends MinecraftRepository
"message VARCHAR(255), " +
"vl INT, " +
"server VARCHAR(32), " +
"metadata VARCHAR(10), " +
"PRIMARY KEY (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 = ?";
BanWaveRepository()
@ -66,22 +69,25 @@ public class BanWaveRepository extends MinecraftRepository
info.setMessage(resultSet.getString(4));
info.setVl(resultSet.getInt(5));
info.setServer(resultSet.getString(6));
info.setMessage(resultSet.getString(7));
callback.run(info);
}
}, 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 ColumnLong("timeToBan", timeToBan),
new ColumnVarChar("hacktype", 64, hackType),
new ColumnVarChar("message", 255, message),
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)

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 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;
import java.util.HashMap;
import java.util.function.Consumer;
import java.util.logging.Level;
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)
{
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);
if (player != null)
@ -250,7 +256,7 @@ public class Punish extends MiniPlugin
if (player != null)
player.kickPlayer(kickReason);
else
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));
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();
_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));
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();
_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;
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[]
{

View File

@ -6,7 +6,8 @@ import mineplex.core.TimingsFix;
import mineplex.core.account.CoreClientManager;
import mineplex.core.achievement.AchievementManager;
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.chat.Chat;
import mineplex.core.chatsnap.SnapshotManager;
@ -139,8 +140,9 @@ public class Clans extends JavaPlugin
Creature creature = new Creature(this);
AntiHack antiHack = require(AntiHack.class);
antiHack.setKick(false);
Bukkit.getScheduler().runTask(this, antiHack::enableNewAnticheat);
GuardianManager guardianManager = require(GuardianManager.class);
Bukkit.getScheduler().runTask(this, antiHack::enableAnticheat);
new EternalGiveawayManager(this, _clientManager, serverStatusManager);
@ -155,7 +157,7 @@ public class Clans extends JavaPlugin
Location spawn = new Location(Bukkit.getWorld("world"), -422, 95, 8);
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);
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);
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);
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);
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.achievement.AchievementManager;
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.blockrestore.BlockRestore;
import mineplex.core.boosters.BoosterManager;
@ -120,10 +121,11 @@ public class ClansHub extends JavaPlugin
Portal portal = new Portal(this, clientManager, serverStatusManager.getCurrentServerName());
AntiHack antiHack = require(AntiHack.class);
GuardianManager guardianManager = require(GuardianManager.class);
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);

View File

@ -10,7 +10,8 @@ import mineplex.core.PacketsInteractionFix;
import mineplex.core.account.CoreClientManager;
import mineplex.core.achievement.AchievementManager;
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.blockrestore.BlockRestore;
import mineplex.core.boosters.BoosterManager;
@ -147,10 +148,11 @@ public class Hub extends JavaPlugin implements IRelation
Portal portal = new Portal(this, clientManager, serverStatusManager.getCurrentServerName());
AntiHack antiHack = require(AntiHack.class);
GuardianManager guardianManager = require(GuardianManager.class);
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);

View File

@ -4,6 +4,7 @@ import mineplex.core.CustomTagFix;
import mineplex.core.FoodDupeFix;
import mineplex.core.PacketsInteractionFix;
import mineplex.core.TimingsFix;
import mineplex.core.antihack.logging.AntihackLogger;
import mineplex.core.chatsnap.SnapshotRepository;
import mineplex.core.customdata.CustomDataManager;
import mineplex.core.chatsnap.SnapshotManager;
@ -65,6 +66,8 @@ import mineplex.core.velocity.VelocityFix;
import mineplex.core.visibility.VisibilityManager;
import mineplex.minecraft.game.core.combat.CombatManager;
import mineplex.minecraft.game.core.damage.DamageManager;
import nautilus.game.arcade.anticheatmetadata.GameInfoMetadata;
import nautilus.game.arcade.game.GameServerConfig;
import net.minecraft.server.v1_8_R3.BiomeBase;
import net.minecraft.server.v1_8_R3.MinecraftServer;
@ -149,8 +152,7 @@ public class Arcade extends JavaPlugin
Punish punish = new Punish(this, webServerAddress, _clientManager);
AntiHack antiHack = require(AntiHack.class);
antiHack.setKick(false);
require(AntiHack.class);
IgnoreManager ignoreManager = new IgnoreManager(this, _clientManager, preferenceManager, portal);
StatsManager statsManager = new StatsManager(this, _clientManager);
@ -187,6 +189,8 @@ public class Arcade extends JavaPlugin
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);
require(AntihackLogger.class).registerMetadata(new GameInfoMetadata());
new GlobalPacketManager(this, _clientManager, serverStatusManager, inventoryManager, _donationManager, petManager, statsManager, _gameManager.getBonusManager().getRewardManager());
//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.PlayerStateChangeEvent;
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.kit.ChampionsKit;
import nautilus.game.arcade.kit.Kit;
@ -740,11 +743,14 @@ public abstract class Game implements Listener
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)
{
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
public void PlayerKillCommandCancel(PlayerCommandPreprocessEvent event)
{