mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2024-09-28 22:47:32 +02:00
Refine fighting checks [ongoing]
This commit is contained in:
parent
bb24ecaa93
commit
836f3af19d
2
pom.xml
2
pom.xml
@ -4,7 +4,7 @@
|
||||
|
||||
<!-- Informations -->
|
||||
<name>NoCheatPlus</name>
|
||||
<version>3.7.3-beta</version>
|
||||
<version>3.7.3</version>
|
||||
<description>Detect and fight the exploitation of various flaws/bugs in Minecraft.</description>
|
||||
<url>http://dev.bukkit.org/server-mods/nocheatplus</url>
|
||||
|
||||
|
@ -84,7 +84,8 @@ public class Combined {
|
||||
// Add time
|
||||
final float amount = ((total - threshold) / threshold * 1000f);
|
||||
data.timeFreeze = Math.max(data.timeFreeze, now + (long) amount);
|
||||
if (cc.yawRateImprobable && Improbable.check(player, 5f * amount / 1000f, now))
|
||||
// TODO: balance (100 ... 200 ) ?
|
||||
if (cc.yawRateImprobable && Improbable.check(player, amount / 100f, now))
|
||||
cancel = true;
|
||||
}
|
||||
if (now < data.timeFreeze) cancel = true;
|
||||
|
@ -43,14 +43,13 @@ public class Critical extends Check {
|
||||
boolean cancel = false;
|
||||
|
||||
// We'll need the PlayerLocation to know some important stuff.
|
||||
PlayerLocation location = new PlayerLocation();
|
||||
final PlayerLocation location = new PlayerLocation();
|
||||
location.set(player.getLocation(), player);
|
||||
|
||||
// Check if the hit was a critical hit (positive fall distance, entity in the air, not on ladder, not in liquid
|
||||
// and without blindness effect).
|
||||
if (player.getFallDistance() > 0f && !location.isOnGround() && !location.isOnLadder() && !location.isInLiquid()
|
||||
&& !player.hasPotionEffect(PotionEffectType.BLINDNESS))
|
||||
|
||||
&& !player.hasPotionEffect(PotionEffectType.BLINDNESS)){
|
||||
// It was a critical hit, now check if the player has jumped or has sent a packet to mislead the server.
|
||||
if (player.getFallDistance() < cc.criticalFallDistance
|
||||
|| Math.abs(player.getVelocity().getY()) < cc.criticalVelocity) {
|
||||
@ -70,8 +69,8 @@ public class Critical extends Check {
|
||||
// should cancel the event.
|
||||
cancel = executeActions(player, data.criticalVL, delta, cc.criticalActions);
|
||||
}
|
||||
}
|
||||
|
||||
location = null;
|
||||
|
||||
return cancel;
|
||||
}
|
||||
|
@ -91,6 +91,7 @@ public class FightConfig extends ACheckConfig {
|
||||
|
||||
public final boolean reachCheck;
|
||||
public final long reachPenalty;
|
||||
public final boolean reachPrecision;
|
||||
public final ActionList reachActions;
|
||||
|
||||
public final boolean selfHitCheck;
|
||||
@ -98,9 +99,17 @@ public class FightConfig extends ACheckConfig {
|
||||
|
||||
public final boolean speedCheck;
|
||||
public final int speedLimit;
|
||||
public final int speedBuckets;
|
||||
public final long speedBucketDur;
|
||||
public final float speedBucketFactor;
|
||||
|
||||
public final int speedShortTermLimit;
|
||||
public final int speedShortTermTicks;
|
||||
public final ActionList speedActions;
|
||||
|
||||
public final boolean yawRateCheck;
|
||||
// Special flags:
|
||||
public final boolean yawRateCheck;
|
||||
public final boolean cancelDead;
|
||||
|
||||
/**
|
||||
* Instantiates a new fight configuration.
|
||||
@ -137,6 +146,7 @@ public class FightConfig extends ACheckConfig {
|
||||
|
||||
reachCheck = data.getBoolean(ConfPaths.FIGHT_REACH_CHECK);
|
||||
reachPenalty = data.getLong(ConfPaths.FIGHT_REACH_PENALTY);
|
||||
reachPrecision = data.getBoolean(ConfPaths.FIGHT_REACH_PRECISION);
|
||||
reachActions = data.getActionList(ConfPaths.FIGHT_REACH_ACTIONS, Permissions.FIGHT_REACH);
|
||||
|
||||
selfHitCheck = data.getBoolean(ConfPaths.FIGHT_SELFHIT_CHECK);
|
||||
@ -144,9 +154,16 @@ public class FightConfig extends ACheckConfig {
|
||||
|
||||
speedCheck = data.getBoolean(ConfPaths.FIGHT_SPEED_CHECK);
|
||||
speedLimit = data.getInt(ConfPaths.FIGHT_SPEED_LIMIT);
|
||||
speedBuckets = data.getInt(ConfPaths.FIGHT_SPEED_BUCKETS_N, 6);
|
||||
speedBucketDur = data.getLong(ConfPaths.FIGHT_SPEED_BUCKETS_DUR, 333);
|
||||
speedBucketFactor = (float) data.getDouble(ConfPaths.FIGHT_SPEED_BUCKETS_FACTOR, 1f);
|
||||
speedShortTermLimit = data.getInt(ConfPaths.FIGHT_SPEED_SHORTTERM_LIMIT);
|
||||
speedShortTermTicks = data.getInt(ConfPaths.FIGHT_SPEED_SHORTTERM_TICKS);
|
||||
speedActions = data.getActionList(ConfPaths.FIGHT_SPEED_ACTIONS, Permissions.FIGHT_SPEED);
|
||||
|
||||
|
||||
yawRateCheck = data.getBoolean(ConfPaths.FIGHT_YAWRATE_CHECK, true);
|
||||
cancelDead = data.getBoolean(ConfPaths.FIGHT_CANCELDEAD);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
@ -52,7 +52,7 @@ public class FightData extends ACheckData {
|
||||
*/
|
||||
public static FightData getData(final Player player) {
|
||||
if (!playersMap.containsKey(player.getName()))
|
||||
playersMap.put(player.getName(), new FightData());
|
||||
playersMap.put(player.getName(), new FightData(FightConfig.getConfig(player)));
|
||||
return playersMap.get(player.getName());
|
||||
}
|
||||
|
||||
@ -73,6 +73,8 @@ public class FightData extends ACheckData {
|
||||
|
||||
public boolean skipNext;
|
||||
|
||||
public long damageTakenTick;
|
||||
|
||||
// Shared
|
||||
|
||||
public String lastWorld = "";
|
||||
@ -104,7 +106,13 @@ public class FightData extends ACheckData {
|
||||
// Data of the SelfHit check.
|
||||
public ActionFrequency selfHitVL = new ActionFrequency(6, 5000);
|
||||
|
||||
// Data of the speed check.
|
||||
public int speedAttacks;
|
||||
public long speedTime;
|
||||
// Data of the frequency check.
|
||||
public final ActionFrequency speedBuckets;
|
||||
public int speedShortTermCount;
|
||||
public int speedShortTermTick;
|
||||
|
||||
|
||||
public FightData(final FightConfig cc){
|
||||
speedBuckets = new ActionFrequency(cc.speedBuckets, cc.speedBucketDur);
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import org.bukkit.event.player.PlayerToggleSprintEvent;
|
||||
import fr.neatmonster.nocheatplus.checks.combined.Combined;
|
||||
import fr.neatmonster.nocheatplus.checks.combined.Improbable;
|
||||
import fr.neatmonster.nocheatplus.players.Permissions;
|
||||
import fr.neatmonster.nocheatplus.utilities.TickTask;
|
||||
|
||||
/*
|
||||
* MM""""""""`M oo dP dP M""MMMMMMMM oo dP
|
||||
@ -96,7 +97,7 @@ public class FightListener implements Listener {
|
||||
data.skipNext = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
boolean cancelled = false;
|
||||
|
||||
final String worldName = player.getWorld().getName();
|
||||
@ -104,7 +105,8 @@ public class FightListener implements Listener {
|
||||
// Check for self hit exploits (mind that projectiles should be excluded)
|
||||
final Entity cbEntity = event.getEntity();
|
||||
if (cbEntity instanceof Player){
|
||||
if (selfHit.isEnabled(player) && selfHit.check(player, cbEntity, data, cc))
|
||||
final Player damagedPlayer = (Player) cbEntity;
|
||||
if (selfHit.isEnabled(player) && selfHit.check(player, damagedPlayer, data, cc))
|
||||
cancelled = true;
|
||||
else{
|
||||
// // Check if improbable
|
||||
@ -114,6 +116,14 @@ public class FightListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
if (cc.cancelDead){
|
||||
if (cbEntity.isDead()) cancelled = true;
|
||||
// Only allow damaging others if taken damage this tick.
|
||||
if (player.isDead() && data.damageTakenTick != TickTask.getTick()){
|
||||
cancelled = true;
|
||||
}
|
||||
}
|
||||
|
||||
final long now = System.currentTimeMillis();
|
||||
|
||||
final boolean worldChanged = !worldName.equals(data.lastWorld);
|
||||
@ -131,6 +141,9 @@ public class FightListener implements Listener {
|
||||
final net.minecraft.server.Entity damaged = ((CraftEntity) cbEntity).getHandle();
|
||||
|
||||
// Run through the main checks.
|
||||
if (!cancelled && speed.isEnabled(player) && speed.check(player, now))
|
||||
cancelled = true;
|
||||
|
||||
if (!cancelled && angle.isEnabled(player) && angle.check(player, worldChanged))
|
||||
cancelled = true;
|
||||
|
||||
@ -146,10 +159,7 @@ public class FightListener implements Listener {
|
||||
if (!cancelled && noSwing.isEnabled(player) && noSwing.check(player))
|
||||
cancelled = true;
|
||||
|
||||
if (!cancelled && reach.isEnabled(player) && reach.check(player, damaged))
|
||||
cancelled = true;
|
||||
|
||||
if (!cancelled && speed.isEnabled(player) && speed.check(player))
|
||||
if (!cancelled && reach.isEnabled(player) && reach.check(player, cbEntity))
|
||||
cancelled = true;
|
||||
|
||||
if (!cancelled && player.isBlocking() && !player.hasPermission(Permissions.MOVING_SURVIVALFLY_BLOCKING))
|
||||
@ -182,11 +192,18 @@ public class FightListener implements Listener {
|
||||
// Filter some unwanted events right now.
|
||||
if (event instanceof EntityDamageByEntityEvent) {
|
||||
final EntityDamageByEntityEvent e = (EntityDamageByEntityEvent) event;
|
||||
if (e.getDamager() instanceof Player)
|
||||
if (e.getCause() == DamageCause.ENTITY_ATTACK)
|
||||
handleNormalDamage(e);
|
||||
final Entity damaged = e.getEntity();
|
||||
if (damaged instanceof Player){
|
||||
FightData.getData((Player) damaged).damageTakenTick = TickTask.getTick();
|
||||
}
|
||||
|
||||
if (e.getDamager() instanceof Player){
|
||||
if (e.getCause() == DamageCause.ENTITY_ATTACK){
|
||||
handleNormalDamage(e);
|
||||
}
|
||||
else if (e.getCause() == DamageCause.CUSTOM)
|
||||
handleCustomDamage(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,17 @@
|
||||
package fr.neatmonster.nocheatplus.checks.fight;
|
||||
|
||||
import net.minecraft.server.Entity;
|
||||
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.EnderDragon;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import fr.neatmonster.nocheatplus.checks.Check;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.checks.combined.Improbable;
|
||||
import fr.neatmonster.nocheatplus.utilities.CheckUtils;
|
||||
import fr.neatmonster.nocheatplus.utilities.LagMeasureTask;
|
||||
|
||||
/*
|
||||
@ -55,15 +57,35 @@ public class Reach extends Check {
|
||||
boolean cancel = false;
|
||||
|
||||
final double distanceLimit = player.getGameMode() == GameMode.SURVIVAL ? SURVIVAL_DISTANCE : CREATIVE_DISTANCE;
|
||||
|
||||
|
||||
// Reference locations to check distance for.
|
||||
// TODO: improve reference location: depending on height difference choose min(foot/hitbox, attacker)
|
||||
final Location dRef;
|
||||
if (damaged instanceof LivingEntity){
|
||||
dRef = ((LivingEntity) damaged).getEyeLocation();
|
||||
}
|
||||
else dRef = damaged.getLocation();
|
||||
final Location pRef = player.getEyeLocation();
|
||||
|
||||
final Vector pRel = dRef.toVector().subtract(pRef.toVector());
|
||||
|
||||
final double mod;
|
||||
if (cc.reachPrecision){
|
||||
// Calculate how fast they are closing in or moving away from each other.
|
||||
mod = 1D;
|
||||
// final Vector vRel = damaged.getVelocity().subtract(player.getVelocity());
|
||||
// System.out.println(vRel.angle(pRel)); // TODO: NaN
|
||||
// final double radial = vRel.length() * Math.cos((vRel.angle(pRel)));
|
||||
// mod = (radial < 0 ? 0.8 : 1.0);
|
||||
// System.out.println(player.getName() + " -> " + pRel.length() + ": " + radial + " => " + mod);
|
||||
}
|
||||
else mod = 1D;
|
||||
// Distance is calculated from eye location to center of targeted. If the player is further away from his target
|
||||
// than allowed, the difference will be assigned to "distance".
|
||||
double distance = CheckUtils.distance(player.getEyeLocation(),
|
||||
damaged.getBukkitEntity().getLocation().add(0D, damaged.getHeadHeight(), 0D))
|
||||
- distanceLimit;
|
||||
double distance = pRel.length() - distanceLimit * mod;
|
||||
|
||||
// Handle the EnderDragon differently.
|
||||
if (damaged.getBukkitEntity() instanceof EnderDragon)
|
||||
if (damaged instanceof EnderDragon)
|
||||
distance -= 6.5D;
|
||||
|
||||
if (distance > 0) {
|
||||
@ -82,11 +104,12 @@ public class Reach extends Check {
|
||||
// Player passed the check, reward him.
|
||||
data.reachVL *= 0.8D;
|
||||
|
||||
// Check if improbable
|
||||
if (distance > -0.3){
|
||||
if (Improbable.check(player, 2.0f, System.currentTimeMillis()))
|
||||
cancel = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if improbable.
|
||||
if (cancel || distance > -1.25){
|
||||
if (Improbable.check(player, (float) (distance + 1.25) / 2f, System.currentTimeMillis()))
|
||||
cancel = true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
package fr.neatmonster.nocheatplus.checks.fight;
|
||||
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import fr.neatmonster.nocheatplus.checks.Check;
|
||||
@ -12,8 +11,8 @@ public class SelfHit extends Check {
|
||||
super(CheckType.FIGHT_SELFHIT);
|
||||
}
|
||||
|
||||
public boolean check(final Player damager, final Entity damaged, final FightData data, final FightConfig cc){
|
||||
if (!damager.getName().equals(((Player) damaged).getName())) return false;
|
||||
public boolean check(final Player damager, final Player damaged, final FightData data, final FightConfig cc){
|
||||
if (!damager.getName().equals(damaged.getName())) return false;
|
||||
|
||||
boolean cancel = false;
|
||||
// Treat self hitting as instant violation.
|
||||
|
@ -9,6 +9,7 @@ import fr.neatmonster.nocheatplus.checks.Check;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.checks.ViolationData;
|
||||
import fr.neatmonster.nocheatplus.utilities.LagMeasureTask;
|
||||
import fr.neatmonster.nocheatplus.utilities.TickTask;
|
||||
|
||||
/*
|
||||
* MP""""""`MM dP
|
||||
@ -21,7 +22,7 @@ import fr.neatmonster.nocheatplus.utilities.LagMeasureTask;
|
||||
* dP
|
||||
*/
|
||||
/**
|
||||
* The Frequency check is used to detect players who are attacking entities too quickly.
|
||||
* The Speed check is used to detect players who are attacking entities too quickly.
|
||||
*/
|
||||
public class Speed extends Check {
|
||||
|
||||
@ -37,34 +38,47 @@ public class Speed extends Check {
|
||||
*
|
||||
* @param player
|
||||
* the player
|
||||
* @param now
|
||||
* @return true, if successful
|
||||
*/
|
||||
public boolean check(final Player player) {
|
||||
public boolean check(final Player player, final long now) {
|
||||
final FightConfig cc = FightConfig.getConfig(player);
|
||||
final FightData data = FightData.getData(player);
|
||||
|
||||
boolean cancel = false;
|
||||
|
||||
// Has one second passed? Reset counters and violation level in that case.
|
||||
if (data.speedTime + 1000L <= System.currentTimeMillis()) {
|
||||
data.speedTime = System.currentTimeMillis();
|
||||
data.speedAttacks = 0;
|
||||
data.speedVL = 0D;
|
||||
|
||||
// Add to frequency.
|
||||
data.speedBuckets.add(now, 1f);
|
||||
|
||||
// Medium term (normalized to one second).
|
||||
final float total = data.speedBuckets.getScore(cc.speedBucketFactor) * 1000f / (float) (cc.speedBucketDur * cc.speedBuckets);
|
||||
|
||||
// Short term.
|
||||
final int tick = TickTask.getTick();
|
||||
if (tick - data.speedShortTermTick < cc.speedShortTermTicks){
|
||||
// Within range, add.
|
||||
data.speedShortTermCount ++;
|
||||
}
|
||||
|
||||
// Count the attack.
|
||||
data.speedAttacks++;
|
||||
else{
|
||||
data.speedShortTermTick = tick;
|
||||
data.speedShortTermCount = 1;
|
||||
}
|
||||
|
||||
final float shortTerm = (float ) data.speedShortTermCount * 1000f / (50f * cc.speedShortTermTicks);
|
||||
|
||||
final float max = Math.max(shortTerm, total);
|
||||
|
||||
// Too many attacks?
|
||||
if (data.speedAttacks > cc.speedLimit) {
|
||||
if (max > cc.speedLimit) {
|
||||
// If there was lag, don't count it towards violation level.
|
||||
if (!LagMeasureTask.skipCheck())
|
||||
data.speedVL += 1;
|
||||
data.speedVL += total - cc.speedLimit;
|
||||
|
||||
// Execute whatever actions are associated with this check and the violation level and find out if we should
|
||||
// cancel the event.
|
||||
cancel = executeActions(player, data.speedVL, 1D, cc.speedActions);
|
||||
cancel = executeActions(player, data.speedVL, total - cc.speedLimit, cc.speedActions);
|
||||
}
|
||||
else data.speedVL *= 0.96;
|
||||
|
||||
return cancel;
|
||||
}
|
||||
|
@ -352,6 +352,7 @@ public abstract class ConfPaths {
|
||||
private static final String FIGHT_REACH = FIGHT + "reach.";
|
||||
public static final String FIGHT_REACH_CHECK = FIGHT_REACH + "active";
|
||||
public static final String FIGHT_REACH_PENALTY = FIGHT_REACH + "penalty";
|
||||
public static final String FIGHT_REACH_PRECISION = FIGHT_REACH + "precision";
|
||||
public static final String FIGHT_REACH_ACTIONS = FIGHT_REACH + "actions";
|
||||
|
||||
public static final String FIGHT_SELFHIT = FIGHT + "selfhit.";
|
||||
@ -362,10 +363,18 @@ public abstract class ConfPaths {
|
||||
private static final String FIGHT_SPEED = FIGHT + "speed.";
|
||||
public static final String FIGHT_SPEED_CHECK = FIGHT_SPEED + "active";
|
||||
public static final String FIGHT_SPEED_LIMIT = FIGHT_SPEED + "limit";
|
||||
private static final String FIGHT_SPEED_BUCKETS = FIGHT_SPEED + "buckets.";
|
||||
public static final String FIGHT_SPEED_BUCKETS_N = FIGHT_SPEED_BUCKETS + "number";
|
||||
public static final String FIGHT_SPEED_BUCKETS_DUR = FIGHT_SPEED_BUCKETS + "duration";
|
||||
public static final String FIGHT_SPEED_BUCKETS_FACTOR = FIGHT_SPEED_BUCKETS + "factor";
|
||||
private static final String FIGHT_SPEED_SHORTTERM = FIGHT_SPEED + "shortterm.";
|
||||
public static final String FIGHT_SPEED_SHORTTERM_LIMIT = FIGHT_SPEED_SHORTTERM + "limit";
|
||||
public static final String FIGHT_SPEED_SHORTTERM_TICKS = FIGHT_SPEED_SHORTTERM + "ticks";
|
||||
public static final String FIGHT_SPEED_ACTIONS = FIGHT_SPEED + "actions";
|
||||
|
||||
private static final String FIGHT_YAWRATE = FIGHT + "yawrate.";
|
||||
public static final String FIGHT_YAWRATE_CHECK = FIGHT_YAWRATE + "active";
|
||||
public static final String FIGHT_CANCELDEAD = FIGHT + "canceldead";
|
||||
|
||||
/*
|
||||
* 888 d8
|
||||
|
@ -240,6 +240,7 @@ public class DefaultConfig extends ConfigFile {
|
||||
* , 88P
|
||||
* "8",P"
|
||||
*/
|
||||
set(ConfPaths.FIGHT_CANCELDEAD, true);
|
||||
set(ConfPaths.FIGHT_YAWRATE_CHECK, true);
|
||||
|
||||
set(ConfPaths.FIGHT_ANGLE_CHECK, true);
|
||||
@ -271,6 +272,7 @@ public class DefaultConfig extends ConfigFile {
|
||||
|
||||
set(ConfPaths.FIGHT_REACH_CHECK, true);
|
||||
set(ConfPaths.FIGHT_REACH_PENALTY, 500);
|
||||
set(ConfPaths.FIGHT_REACH_PRECISION, true);
|
||||
set(ConfPaths.FIGHT_REACH_ACTIONS, "cancel vl>10 log:freach:2:5:if cancel");
|
||||
|
||||
set(ConfPaths.FIGHT_SELFHIT_CHECK, true);
|
||||
@ -279,6 +281,8 @@ public class DefaultConfig extends ConfigFile {
|
||||
set(ConfPaths.FIGHT_SPEED_CHECK, true);
|
||||
set(ConfPaths.FIGHT_SPEED_LIMIT, 15);
|
||||
set(ConfPaths.FIGHT_SPEED_ACTIONS, "log:fspeed:0:5:if cancel");
|
||||
set(ConfPaths.FIGHT_SPEED_SHORTTERM_TICKS, 7);
|
||||
set(ConfPaths.FIGHT_SPEED_SHORTTERM_LIMIT, 6);
|
||||
|
||||
/*
|
||||
* 888 d8
|
||||
|
Loading…
Reference in New Issue
Block a user