diff --git a/src/fr/neatmonster/nocheatplus/checks/chat/ChatListener.java b/src/fr/neatmonster/nocheatplus/checks/chat/ChatListener.java index 6c6ebf4f..fe83c9f1 100644 --- a/src/fr/neatmonster/nocheatplus/checks/chat/ChatListener.java +++ b/src/fr/neatmonster/nocheatplus/checks/chat/ChatListener.java @@ -95,8 +95,13 @@ public class ChatListener implements Listener { return; } - // This type of event is derived from PlayerChatEvent, therefore just treat it like that. - onPlayerChat(event); + // First the color check. + if (color.isEnabled(player)) + event.setMessage(color.check(player, event.getMessage())); + + // Then the no pwnage check. + if (noPwnage.isEnabled(player) && noPwnage.check(player)) + player.kickPlayer(Check.removeColors(ChatConfig.getConfig(player).noPwnageKickMessage)); } /** diff --git a/src/fr/neatmonster/nocheatplus/checks/chat/NoPwnage.java b/src/fr/neatmonster/nocheatplus/checks/chat/NoPwnage.java index 1900f990..ac290453 100644 --- a/src/fr/neatmonster/nocheatplus/checks/chat/NoPwnage.java +++ b/src/fr/neatmonster/nocheatplus/checks/chat/NoPwnage.java @@ -6,6 +6,7 @@ import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerChatEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.player.PlayerEvent; import fr.neatmonster.nocheatplus.actions.ParameterName; import fr.neatmonster.nocheatplus.checks.Check; @@ -118,7 +119,7 @@ public class NoPwnage extends Check { * the event * @return true, if successful */ - public boolean check(final Player player, final PlayerChatEvent event) { + public boolean check(final Player player, final PlayerEvent event) { final ChatConfig cc = ChatConfig.getConfig(player); final ChatData data = ChatData.getData(player); data.noPwnageVL = 0D; @@ -126,7 +127,11 @@ public class NoPwnage extends Check { boolean cancel = false; if (!data.noPwnageHasFilledCaptcha) { - final String message = event.getMessage(); + String message = ""; + if (event instanceof PlayerChatEvent) + message = ((PlayerChatEvent) event).getMessage(); + else if (event instanceof PlayerCommandPreprocessEvent) + message = ((PlayerCommandPreprocessEvent) event).getMessage(); final boolean isCommand = event instanceof PlayerCommandPreprocessEvent; final long now = System.currentTimeMillis(); @@ -159,7 +164,10 @@ public class NoPwnage extends Check { } // Cancel the event and return. - event.setCancelled(true); + if (event instanceof PlayerChatEvent) + ((PlayerChatEvent) event).setCancelled(true); + else if (event instanceof PlayerCommandPreprocessEvent) + ((PlayerCommandPreprocessEvent) event).setCancelled(true); return cancel; } @@ -226,14 +234,20 @@ public class NoPwnage extends Check { player.sendMessage(replaceColors(cc.noPwnageCaptchaQuestion.replace("[captcha]", data.noPwnageGeneratedCaptcha))); data.noPwnageHasStartedCaptcha = true; - event.setCancelled(true); + if (event instanceof PlayerChatEvent) + ((PlayerChatEvent) event).setCancelled(true); + else if (event instanceof PlayerCommandPreprocessEvent) + ((PlayerCommandPreprocessEvent) event).setCancelled(true); } else { lastBanCausingMessage = message; data.noPwnageLastWarningTime = lastBanCausingMessageTime = now; if (cc.noPwnageWarnOthersCheck) Bukkit.broadcastMessage(replaceColors(cc.noPwnageWarnOthersMessage.replace("[player]", player.getName()))); - event.setCancelled(true); + if (event instanceof PlayerChatEvent) + ((PlayerChatEvent) event).setCancelled(true); + else if (event instanceof PlayerCommandPreprocessEvent) + ((PlayerCommandPreprocessEvent) event).setCancelled(true); // Dispatch a no pwnage event (API). final NoPwnageEvent e = new NoPwnageEvent(player); diff --git a/src/fr/neatmonster/nocheatplus/checks/fight/FightConfig.java b/src/fr/neatmonster/nocheatplus/checks/fight/FightConfig.java index 63741791..22af2157 100644 --- a/src/fr/neatmonster/nocheatplus/checks/fight/FightConfig.java +++ b/src/fr/neatmonster/nocheatplus/checks/fight/FightConfig.java @@ -70,6 +70,10 @@ public class FightConfig { public final boolean instantHealCheck; public final ActionList instantHealActions; + public final boolean knockbackCheck; + public final long knockbackInterval; + public final ActionList knockbackActions; + /** * Instantiates a new fight configuration. * @@ -95,5 +99,9 @@ public class FightConfig { instantHealCheck = data.getBoolean(ConfPaths.FIGHT_INSTANTHEAL_CHECK); instantHealActions = data.getActionList(ConfPaths.FIGHT_INSTANTHEAL_ACTIONS, Permissions.FIGHT_INSTANTHEAL); + + knockbackCheck = data.getBoolean(ConfPaths.FIGHT_KNOCKBACK_CHECK); + knockbackInterval = data.getLong(ConfPaths.FIGHT_KNOCKBACK_INTERVAL); + knockbackActions = data.getActionList(ConfPaths.FIGHT_KNOCKBACK_ACTIONS, Permissions.FIGHT_KNOCKBACK); } } diff --git a/src/fr/neatmonster/nocheatplus/checks/fight/FightData.java b/src/fr/neatmonster/nocheatplus/checks/fight/FightData.java index 2de0169f..abfb1ebb 100644 --- a/src/fr/neatmonster/nocheatplus/checks/fight/FightData.java +++ b/src/fr/neatmonster/nocheatplus/checks/fight/FightData.java @@ -44,6 +44,7 @@ public class FightData { public double directionVL; public double godModeVL; public double instantHealVL; + public double knockbackVL; // Data of the angle check. public TreeMap angleHits = new TreeMap(); @@ -60,4 +61,7 @@ public class FightData { public int instantHealBuffer; public long instantHealLastTime; + // Data of the knockback check. + public long knockbackSprintTime; + } diff --git a/src/fr/neatmonster/nocheatplus/checks/fight/Knockback.java b/src/fr/neatmonster/nocheatplus/checks/fight/Knockback.java new file mode 100644 index 00000000..6402e8ed --- /dev/null +++ b/src/fr/neatmonster/nocheatplus/checks/fight/Knockback.java @@ -0,0 +1,94 @@ +package fr.neatmonster.nocheatplus.checks.fight; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import fr.neatmonster.nocheatplus.actions.ParameterName; +import fr.neatmonster.nocheatplus.checks.Check; +import fr.neatmonster.nocheatplus.checks.CheckEvent; +import fr.neatmonster.nocheatplus.players.Permissions; +import fr.neatmonster.nocheatplus.utilities.LagMeasureTask; + +/* + * M""MMMMM""M dP dP dP + * M MMMM' .M 88 88 88 + * M .MM 88d888b. .d8888b. .d8888b. 88 .dP 88d888b. .d8888b. .d8888b. 88 .dP + * M MMMb. YM 88' `88 88' `88 88' `"" 88888" 88' `88 88' `88 88' `"" 88888" + * M MMMMb M 88 88 88. .88 88. ... 88 `8b. 88. .88 88. .88 88. ... 88 `8b. + * M MMMMM M dP dP `88888P' `88888P' dP `YP 88Y8888' `88888P8 `88888P' dP `YP + * MMMMMMMMMMM + */ +/** + * A check used to verify if players aren't "knockbacking" other players when it's not technically possible. + */ +public class Knockback extends Check { + + /** + * The event triggered by this check. + */ + public class KnockbackEvent extends CheckEvent { + + /** + * Instantiates a new knockback event. + * + * @param player + * the player + */ + public KnockbackEvent(final Player player) { + super(player); + } + } + + /** + * Checks a player. + * + * @param player + * the player + * @return true, if successful + */ + public boolean check(final Player player) { + final FightConfig cc = FightConfig.getConfig(player); + final FightData data = FightData.getData(player); + + boolean cancel = false; + + // How long ago has the player started sprinting? + if (data.knockbackSprintTime > 0L + && System.currentTimeMillis() - data.knockbackSprintTime < cc.knockbackInterval) { + + // Player failed the check, but this is influenced by lag, so don't do it if there was lag. + if (!LagMeasureTask.skipCheck()) + // Increment the violation level + data.knockbackVL += cc.knockbackInterval - System.currentTimeMillis() + data.knockbackSprintTime; + + // Dispatch a knockback event (API). + final KnockbackEvent e = new KnockbackEvent(player); + Bukkit.getPluginManager().callEvent(e); + + // Execute whatever actions are associated with this check and the violation level and find out if we should + // cancel the event. + cancel = !e.isCancelled() && executeActions(player, cc.knockbackActions, data.knockbackVL); + } + + return cancel; + } + + /* (non-Javadoc) + * @see fr.neatmonster.nocheatplus.checks.Check#getParameter(fr.neatmonster.nocheatplus.actions.ParameterName, org.bukkit.entity.Player) + */ + @Override + public String getParameter(final ParameterName wildcard, final Player player) { + if (wildcard == ParameterName.VIOLATIONS) + return String.valueOf(Math.round(FightData.getData(player).knockbackVL)); + else + return super.getParameter(wildcard, player); + } + + /* (non-Javadoc) + * @see fr.neatmonster.nocheatplus.checks.Check#isEnabled(org.bukkit.entity.Player) + */ + @Override + protected boolean isEnabled(final Player player) { + return !player.hasPermission(Permissions.FIGHT_KNOCKBACK) && FightConfig.getConfig(player).knockbackCheck; + } +} diff --git a/src/fr/neatmonster/nocheatplus/config/ConfPaths.java b/src/fr/neatmonster/nocheatplus/config/ConfPaths.java index 575fc107..441d3132 100644 --- a/src/fr/neatmonster/nocheatplus/config/ConfPaths.java +++ b/src/fr/neatmonster/nocheatplus/config/ConfPaths.java @@ -221,6 +221,11 @@ public abstract class ConfPaths { public static final String FIGHT_INSTANTHEAL_CHECK = FIGHT_INSTANTHEAL + "active"; public static final String FIGHT_INSTANTHEAL_ACTIONS = FIGHT_INSTANTHEAL + "actions"; + private static final String FIGHT_KNOCKBACK = FIGHT + "knockback."; + public static final String FIGHT_KNOCKBACK_CHECK = FIGHT_KNOCKBACK + "active"; + public static final String FIGHT_KNOCKBACK_INTERVAL = FIGHT_KNOCKBACK + "interval"; + public static final String FIGHT_KNOCKBACK_ACTIONS = FIGHT_KNOCKBACK + "actions"; + /* * e e ,e, * d8b d8b e88 88e Y8b Y888P " 888 8e e88 888 diff --git a/src/fr/neatmonster/nocheatplus/config/DefaultConfig.java b/src/fr/neatmonster/nocheatplus/config/DefaultConfig.java index 529494f1..29fbc112 100644 --- a/src/fr/neatmonster/nocheatplus/config/DefaultConfig.java +++ b/src/fr/neatmonster/nocheatplus/config/DefaultConfig.java @@ -197,6 +197,10 @@ public class DefaultConfig extends ConfigFile { set(ConfPaths.FIGHT_INSTANTHEAL_CHECK, true); set(ConfPaths.FIGHT_INSTANTHEAL_ACTIONS, "log:instantheal:1:1:if cancel"); + set(ConfPaths.FIGHT_KNOCKBACK_CHECK, true); + set(ConfPaths.FIGHT_KNOCKBACK_INTERVAL, 50L); + set(ConfPaths.FIGHT_KNOCKBACK_ACTIONS, "cancel vl>50 log:knockback:0:5:cif cancel"); + /* * e e ,e, * d8b d8b e88 88e Y8b Y888P " 888 8e e88 888 @@ -269,6 +273,7 @@ public class DefaultConfig extends ConfigFile { set(ConfPaths.STRINGS + ".godmode", start + "avoided taking damage or lagging" + end); set(ConfPaths.STRINGS + ".instantheal", start + "tried to regenerate health faster than normal" + end); set(ConfPaths.STRINGS + ".kick", "kick [player]"); + set(ConfPaths.STRINGS + ".knockback", start + "tried to do a knockback but wasn't technically sprinting" + end); set(ConfPaths.STRINGS + ".morepackets", start + "sent [packets] more packet(s) than expected" + end); set(ConfPaths.STRINGS + ".nofall", start + "tried to avoid fall damage for ~[falldistance] block(s)" + end); set(ConfPaths.STRINGS + ".nopwnage", start + "acted like a spambot (IP: [ip])" + end); diff --git a/src/fr/neatmonster/nocheatplus/players/Permissions.java b/src/fr/neatmonster/nocheatplus/players/Permissions.java index 5bacbfe7..b9dcd00c 100644 --- a/src/fr/neatmonster/nocheatplus/players/Permissions.java +++ b/src/fr/neatmonster/nocheatplus/players/Permissions.java @@ -117,7 +117,8 @@ public class Permissions { public static final String FIGHT_CRITICAL = FIGHT + ".critical"; public static final String FIGHT_DIRECTION = FIGHT + ".direction"; public static final String FIGHT_GODMODE = FIGHT + ".godmode"; - public static final String FIGHT_INSTANTHEAL = FIGHT + "instantheal"; + public static final String FIGHT_INSTANTHEAL = FIGHT + ".instantheal"; + public static final String FIGHT_KNOCKBACK = FIGHT + ".knockback"; /* * e e ,e,