From 66fe28dd934340a7f84fae0c6ffe7e131de2e84a Mon Sep 17 00:00:00 2001 From: asofold Date: Tue, 18 Sep 2012 17:25:23 +0200 Subject: [PATCH] Add yawrate check to fight/combined. Adjust angle check. --- .../nocheatplus/checks/combined/Combined.java | 105 ++++++++++++++++++ .../checks/combined/CombinedConfig.java | 6 + .../checks/combined/CombinedData.java | 4 +- .../checks/combined/CombinedListener.java | 34 +++--- .../checks/combined/Improbable.java | 27 ----- .../nocheatplus/checks/fight/Angle.java | 14 ++- .../nocheatplus/checks/fight/FightConfig.java | 4 + .../nocheatplus/checks/fight/FightData.java | 4 + .../checks/fight/FightListener.java | 12 +- .../nocheatplus/config/ConfPaths.java | 6 + .../nocheatplus/config/DefaultConfig.java | 4 + 11 files changed, 172 insertions(+), 48 deletions(-) create mode 100644 src/fr/neatmonster/nocheatplus/checks/combined/Combined.java diff --git a/src/fr/neatmonster/nocheatplus/checks/combined/Combined.java b/src/fr/neatmonster/nocheatplus/checks/combined/Combined.java new file mode 100644 index 00000000..d0c2b1f3 --- /dev/null +++ b/src/fr/neatmonster/nocheatplus/checks/combined/Combined.java @@ -0,0 +1,105 @@ +package fr.neatmonster.nocheatplus.checks.combined; + +import org.bukkit.entity.Player; + + +/** + * Static access API for shared use. This is actually not really a check, but access to combined or shared data. + * @author mc_dev + * + */ +public class Combined { + + /** + * Check if a penalty is set by changing horizontal facing dierection too often. + * @param player + * @param yaw + * @param now + * @param worldName + * @return + */ + public static final boolean checkYaw(final Player player, final float yaw, final long now, final String worldName){ + return checkYaw(player, yaw, now, worldName, CombinedData.getData(player)); + } + + /** + * Feed horizontal facing direction. + * @param player + * @param yaw + * @param now + * @param worldName + */ + public static final void feedYaw(final Player player, final float yaw, final long now, final String worldName){ + feedYaw(player, yaw, now, worldName, CombinedData.getData(player)); + } + + /** + * Update the yaw change data. + * @param player + * @param yaw + * @param now + * @param worldName + * @param data + */ + private static final void feedYaw(final Player player, final float yaw, final long now, final String worldName, final CombinedData data) { + // Reset on world change or timeout. + if (now - data.lastYawTime > 999 || !worldName.equals(data.lastWorld)){ + data.lastYaw = yaw; + data.lastYawTime = now; + data.lastWorld = worldName; + } + + final float yawDiff = (yaw - data.lastYaw) % 180; + final long elapsed = now - data.lastYawTime; + + // Set data to current state. + data.lastYaw = yaw; + data.lastYawTime = now; + + final float dAbs = Math.abs(yawDiff); + final float dNorm = (float) dAbs / (float) (1 + elapsed); + + data.yawFreq.add(now, dNorm); + } + + /** + * This calls feedLastYaw and does nothing but set the freezing time to be used by whatever check. + * @param player + * @param yaw + * @param now + * @param worldName + * @return + */ + private static final boolean checkYaw(Player player, float yaw, long now, final String worldName, final CombinedData data) { + + feedYaw(player, yaw, now, worldName, data); + + final CombinedConfig cc = CombinedConfig.getConfig(player); + + // Angle diff per second + final float total = Math.max(data.yawFreq.getScore(1f), data.yawFreq.getScore(0) * 3f); + final float threshold = cc.lastYawRate; + if (total > threshold){ + // Add time + data.timeFreeze = Math.max(data.timeFreeze, now + (long) ((total - threshold) / threshold * 1000f)); + } + return now < data.timeFreeze; + } + + /** + * Allow to pass a config flag if to check or only to feed. + * @param player + * @param yaw + * @param now + * @param worldName + * @param yawRateCheck If to actually check the yaw rate, or just feed. + * @return + */ + public static final boolean checkYaw(final Player player, final float yaw, final long now, final String worldName, final boolean yawRateCheck) { + if (yawRateCheck) return checkYaw(player, yaw, now, worldName); + else { + feedYaw(player, yaw, now, worldName); + return false; + } + } +} diff --git a/src/fr/neatmonster/nocheatplus/checks/combined/CombinedConfig.java b/src/fr/neatmonster/nocheatplus/checks/combined/CombinedConfig.java index 4c7dbf54..492f4632 100644 --- a/src/fr/neatmonster/nocheatplus/checks/combined/CombinedConfig.java +++ b/src/fr/neatmonster/nocheatplus/checks/combined/CombinedConfig.java @@ -37,14 +37,20 @@ public class CombinedConfig extends ACheckConfig { return cc; } + /** Do mind that this flag is not used by all compinents. */ public final boolean improbableCheck; public final float improbableLevel; public final ActionList improbableActions; + // Last yaw tracking + public final float lastYawRate; + public CombinedConfig(final ConfigFile config) { improbableCheck = config.getBoolean(ConfPaths.COMBINED_IMPROBABLE_CHECK, false); improbableLevel = (float) config.getDouble(ConfPaths.COMBINED_IMPROBABLE_LEVEL, 300); improbableActions = config.getActionList(ConfPaths.COMBINED_IMPROBABLE_ACTIONS, Permissions.COMBINED_IMPROBABLE); + + lastYawRate = config.getInt(ConfPaths.COMBINED_YAWRATE_RATE); } @Override diff --git a/src/fr/neatmonster/nocheatplus/checks/combined/CombinedData.java b/src/fr/neatmonster/nocheatplus/checks/combined/CombinedData.java index 4510d25e..ea0e04ba 100644 --- a/src/fr/neatmonster/nocheatplus/checks/combined/CombinedData.java +++ b/src/fr/neatmonster/nocheatplus/checks/combined/CombinedData.java @@ -46,11 +46,13 @@ public class CombinedData extends ACheckData { public float lastYaw; public long lastYawTime; - public final ActionFrequency yawFreq = new ActionFrequency(4, 500); + public final ActionFrequency yawFreq = new ActionFrequency(3, 333); public long timeFreeze = 0; public final ActionFrequency improbableCount = new ActionFrequency(20, 3000); + + public String lastWorld = ""; public CombinedData(final Player player){ // final CombinedConfig cc = CombinedConfig.getConfig(player); diff --git a/src/fr/neatmonster/nocheatplus/checks/combined/CombinedListener.java b/src/fr/neatmonster/nocheatplus/checks/combined/CombinedListener.java index ef4bb560..17e756eb 100644 --- a/src/fr/neatmonster/nocheatplus/checks/combined/CombinedListener.java +++ b/src/fr/neatmonster/nocheatplus/checks/combined/CombinedListener.java @@ -1,10 +1,13 @@ package fr.neatmonster.nocheatplus.checks.combined; +import org.bukkit.Location; 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.PlayerMoveEvent; +import org.bukkit.event.player.PlayerToggleSneakEvent; +import org.bukkit.event.player.PlayerToggleSprintEvent; /** * @@ -19,23 +22,26 @@ public class CombinedListener implements Listener { this.improbable = new Improbable(); } -// @EventHandler(priority=EventPriority.LOW) -// public void onPlayerToggleSneak(final PlayerToggleSneakEvent event){ -// // Check also in case of cancelled events. -// if (Improbable.check(event.getPlayer(), 0.35f, System.currentTimeMillis())) event.setCancelled(true); -// } -// -// @EventHandler(priority=EventPriority.LOW) -// public void onPlayerToggleSprint(final PlayerToggleSprintEvent event){ -// // Check also in case of cancelled events. -// if (Improbable.check(event.getPlayer(), 0.35f, System.currentTimeMillis())) event.setCancelled(true); -// } + @EventHandler(priority=EventPriority.LOW) + public void onPlayerToggleSneak(final PlayerToggleSneakEvent event){ + // Check also in case of cancelled events. + if (Improbable.check(event.getPlayer(), 0.35f, System.currentTimeMillis())) event.setCancelled(true); + } - @EventHandler(priority=EventPriority.MONITOR) + @EventHandler(priority=EventPriority.LOW) + public void onPlayerToggleSprint(final PlayerToggleSprintEvent event){ + // Check also in case of cancelled events. + if (Improbable.check(event.getPlayer(), 0.35f, System.currentTimeMillis())) event.setCancelled(true); + } + + @EventHandler(priority=EventPriority.MONITOR, ignoreCancelled = false) public final void onPlayerMove(final PlayerMoveEvent event){ - final Player player =event.getPlayer(); + // Experimental + final Player player = event.getPlayer(); // Just add the yaw to the list. - Improbable.checkYaw(player, player.getLocation().getYaw(), System.currentTimeMillis()); + final Location loc = player.getLocation(); + final String worldName = loc.getWorld().getName(); + Combined.feedYaw(player, loc.getYaw(), System.currentTimeMillis(), worldName); } // (possibly other types of events, but these combine with fighting). diff --git a/src/fr/neatmonster/nocheatplus/checks/combined/Improbable.java b/src/fr/neatmonster/nocheatplus/checks/combined/Improbable.java index e34e2008..38158be7 100644 --- a/src/fr/neatmonster/nocheatplus/checks/combined/Improbable.java +++ b/src/fr/neatmonster/nocheatplus/checks/combined/Improbable.java @@ -26,10 +26,6 @@ public class Improbable extends Check { public static final boolean check(final Player player, final float weight, final long now){ return instance.checkImprobable(player, weight, now); } - - public static final boolean checkYaw(final Player player, final float yaw, final long now){ - return instance.checkLastYaw(player, yaw, now); - } //////////////////////////////////// // Instance methods. @@ -67,28 +63,5 @@ public class Improbable extends Check { data.improbableVL *= 0.95; return cancel; } - - private boolean checkLastYaw(Player player, float yaw, long now) { - if (!isEnabled(player)) return false; - final CombinedData data = CombinedData.getData(player); -// final CombinedConfig cc = CombinedConfig.getConfig(player); - final float yawDiff = (yaw - data.lastYaw) % 180; - - -// final long elapsed = now - data.lastYawTime; - boolean cancel = false; - - if (now < data.timeFreeze) cancel = true; - - final float dAbs = Math.abs(yawDiff); - data.yawFreq.add(now, (float) dAbs); // *3f / ((float) (elapsed + 1)) ); - if (dAbs > 30) data.timeFreeze = now + (long) dAbs * 3; -// System.out.println("yawDiff " + player.getName() + ": " + yawDiff + " (" + elapsed+ ") - " + data.yawFreq.getScore(1f)); - - // Set data to current state. - data.lastYaw = yaw; - data.lastYawTime = now; - return cancel; - } } diff --git a/src/fr/neatmonster/nocheatplus/checks/fight/Angle.java b/src/fr/neatmonster/nocheatplus/checks/fight/Angle.java index 26d87c68..7efb5a56 100644 --- a/src/fr/neatmonster/nocheatplus/checks/fight/Angle.java +++ b/src/fr/neatmonster/nocheatplus/checks/fight/Angle.java @@ -38,11 +38,17 @@ public class Angle extends Check { * * @param player * the player + * @param worldChanged * @return true, if successful */ - public boolean check(final Player player) { + public boolean check(final Player player, final boolean worldChanged) { final FightConfig cc = FightConfig.getConfig(player); final FightData data = FightData.getData(player); + + if (worldChanged){ + // TODO: clear some data. + data.angleHits.clear(); + } boolean cancel = false; @@ -69,13 +75,15 @@ public class Angle extends Check { for (final long time : data.angleHits.descendingKeySet()) { final Location location = data.angleHits.get(time); // We need a previous location to calculate deltas. - if (previousLocation != null && location.getWorld().getName().equals(previousLocation.getWorld().getName())) { + if (previousLocation != null){ // && location.getWorld().getName().equals(previousLocation.getWorld().getName())) { + // (Risks exceptions on reloading). // Calculate the distance between the two locations. deltaMove += previousLocation.distanceSquared(location); // Calculate the time elapsed between the two hits. deltaTime += previousTime - time; // Calculate the difference of the yaw between the two locations. - deltaYaw += (previousLocation.getYaw() - location.getYaw()) % 360f; + final float dYaw = (previousLocation.getYaw() - location.getYaw()) % 180; + deltaYaw += Math.abs(dYaw); } // Remember the current time and location. previousTime = time; diff --git a/src/fr/neatmonster/nocheatplus/checks/fight/FightConfig.java b/src/fr/neatmonster/nocheatplus/checks/fight/FightConfig.java index f5d5e5ba..4ba827bd 100644 --- a/src/fr/neatmonster/nocheatplus/checks/fight/FightConfig.java +++ b/src/fr/neatmonster/nocheatplus/checks/fight/FightConfig.java @@ -99,6 +99,8 @@ public class FightConfig extends ACheckConfig { public final boolean speedCheck; public final int speedLimit; public final ActionList speedActions; + + public final boolean yawRateCheck; /** * Instantiates a new fight configuration. @@ -143,6 +145,8 @@ public class FightConfig extends ACheckConfig { speedCheck = data.getBoolean(ConfPaths.FIGHT_SPEED_CHECK); speedLimit = data.getInt(ConfPaths.FIGHT_SPEED_LIMIT); speedActions = data.getActionList(ConfPaths.FIGHT_SPEED_ACTIONS, Permissions.FIGHT_SPEED); + + yawRateCheck = data.getBoolean(ConfPaths.FIGHT_YAWRATE_CHECK, true); } /* (non-Javadoc) diff --git a/src/fr/neatmonster/nocheatplus/checks/fight/FightData.java b/src/fr/neatmonster/nocheatplus/checks/fight/FightData.java index bf1bd683..3546a325 100644 --- a/src/fr/neatmonster/nocheatplus/checks/fight/FightData.java +++ b/src/fr/neatmonster/nocheatplus/checks/fight/FightData.java @@ -72,6 +72,10 @@ public class FightData extends ACheckData { public double speedVL; public boolean skipNext; + + // Shared + + public String lastWorld = ""; // Data of the angle check. public TreeMap angleHits = new TreeMap(); diff --git a/src/fr/neatmonster/nocheatplus/checks/fight/FightListener.java b/src/fr/neatmonster/nocheatplus/checks/fight/FightListener.java index 5a4fdcd0..d631dc1e 100644 --- a/src/fr/neatmonster/nocheatplus/checks/fight/FightListener.java +++ b/src/fr/neatmonster/nocheatplus/checks/fight/FightListener.java @@ -15,6 +15,7 @@ import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; import org.bukkit.event.player.PlayerAnimationEvent; 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; @@ -98,6 +99,8 @@ public class FightListener implements Listener { boolean cancelled = false; + final String worldName = player.getWorld().getName(); + // Check for self hit exploits (mind that projectiles should be excluded) final Entity cbEntity = event.getEntity(); if (cbEntity instanceof Player){ @@ -113,10 +116,11 @@ public class FightListener implements Listener { final long now = System.currentTimeMillis(); + final boolean worldChanged = !worldName.equals(data.lastWorld); + // Improbable yaw: - if (Improbable.checkYaw(player, player.getLocation().getYaw(), now)){ + if (Combined.checkYaw(player, player.getLocation().getYaw(), now, worldName, cc.yawRateCheck)){ cancelled = true; -// System.out.println(player.getName() + " <- cancelled attack by yaw."); } // Combined speed: @@ -127,7 +131,7 @@ public class FightListener implements Listener { final net.minecraft.server.Entity damaged = ((CraftEntity) cbEntity).getHandle(); // Run through the main checks. - if (!cancelled && angle.isEnabled(player) && angle.check(player)) + if (!cancelled && angle.isEnabled(player) && angle.check(player, worldChanged)) cancelled = true; if (!cancelled && critical.isEnabled(player) && critical.check(player)) @@ -154,6 +158,8 @@ public class FightListener implements Listener { // One of the checks requested the event to be cancelled, so do it. if (cancelled) event.setCancelled(cancelled); + + data.lastWorld = worldName; } /** diff --git a/src/fr/neatmonster/nocheatplus/config/ConfPaths.java b/src/fr/neatmonster/nocheatplus/config/ConfPaths.java index f02e95c7..34079dd4 100644 --- a/src/fr/neatmonster/nocheatplus/config/ConfPaths.java +++ b/src/fr/neatmonster/nocheatplus/config/ConfPaths.java @@ -301,6 +301,9 @@ public abstract class ConfPaths { public static final String COMBINED_IMPROBABLE_ACTIONS = COMBINED_IMPROBABLE + "actions"; + private static final String COMBINED_YAWRATE = COMBINED + "yawrate."; + public static final String COMBINED_YAWRATE_RATE = COMBINED_YAWRATE + "rate"; + /* * 888'Y88 ,e, 888 d8 * 888 ,'Y " e88 888 888 ee d88 @@ -359,6 +362,9 @@ public abstract class ConfPaths { public static final String FIGHT_SPEED_CHECK = FIGHT_SPEED + "active"; public static final String FIGHT_SPEED_LIMIT = FIGHT_SPEED + "limit"; 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"; /* * 888 d8 diff --git a/src/fr/neatmonster/nocheatplus/config/DefaultConfig.java b/src/fr/neatmonster/nocheatplus/config/DefaultConfig.java index 528fcaa8..3ece37b4 100644 --- a/src/fr/neatmonster/nocheatplus/config/DefaultConfig.java +++ b/src/fr/neatmonster/nocheatplus/config/DefaultConfig.java @@ -228,6 +228,8 @@ public class DefaultConfig extends ConfigFile { set(ConfPaths.COMBINED_IMPROBABLE_FASTBREAK_CHECK, false); set(ConfPaths.COMBINED_IMPROBABLE_ACTIONS, "cancel log:improbable:2:8:if"); + set(ConfPaths.COMBINED_YAWRATE_RATE , "380"); + /* * 888'Y88 ,e, 888 d8 * 888 ,'Y " e88 888 888 ee d88 @@ -237,6 +239,8 @@ public class DefaultConfig extends ConfigFile { * , 88P * "8",P" */ + set(ConfPaths.FIGHT_YAWRATE_CHECK, true); + set(ConfPaths.FIGHT_ANGLE_CHECK, true); set(ConfPaths.FIGHT_ANGLE_THRESHOLD, 50); set(ConfPaths.FIGHT_ANGLE_ACTIONS, "cancel vl>100 log:angle:3:5:f cancel vl>250 log:angle:0:5:cif cancel");