From c47c2d98e82e7c4ba50a4742ef62dc46cab63ad7 Mon Sep 17 00:00:00 2001 From: Evenprime Date: Sun, 3 Apr 2011 20:36:06 +0200 Subject: [PATCH] Code Refactoring plus preparations for custom events --- plugin.yml | 2 +- .../bukkit/nocheat/CustomAction.java | 20 -- .../bukkit/nocheat/NoCheatConfiguration.java | 16 +- .../evenprime/bukkit/nocheat/NoCheatData.java | 4 + .../bukkit/nocheat/NoCheatPlugin.java | 6 + .../bukkit/nocheat/actions/Action.java | 9 +- .../bukkit/nocheat/actions/CancelAction.java | 9 +- .../bukkit/nocheat/actions/CustomAction.java | 12 + .../bukkit/nocheat/actions/LogAction.java | 25 +- .../bukkit/nocheat/checks/AirbuildCheck.java | 35 ++- .../bukkit/nocheat/checks/MovingCheck.java | 253 +++++++----------- .../bukkit/nocheat/checks/SpeedhackCheck.java | 15 +- 12 files changed, 192 insertions(+), 214 deletions(-) delete mode 100644 src/cc/co/evenprime/bukkit/nocheat/CustomAction.java create mode 100644 src/cc/co/evenprime/bukkit/nocheat/actions/CustomAction.java diff --git a/plugin.yml b/plugin.yml index 9441d2cb..0922b475 100644 --- a/plugin.yml +++ b/plugin.yml @@ -3,7 +3,7 @@ name: NoCheatPlugin author: Evenprime main: cc.co.evenprime.bukkit.nocheat.NoCheatPlugin -version: 0.7.7b +version: 0.7.7c commands: nocheat: diff --git a/src/cc/co/evenprime/bukkit/nocheat/CustomAction.java b/src/cc/co/evenprime/bukkit/nocheat/CustomAction.java deleted file mode 100644 index 6795dbf7..00000000 --- a/src/cc/co/evenprime/bukkit/nocheat/CustomAction.java +++ /dev/null @@ -1,20 +0,0 @@ -package cc.co.evenprime.bukkit.nocheat; - -import org.bukkit.entity.Player; - -import cc.co.evenprime.bukkit.nocheat.actions.Action; - -public class CustomAction implements Action { - - private final int id; - private final String command; - - public CustomAction(int id, String command) { - this.id = id; - this.command = command; - } - - public void execute(Player player) { - // TODO: add command execution - } -} diff --git a/src/cc/co/evenprime/bukkit/nocheat/NoCheatConfiguration.java b/src/cc/co/evenprime/bukkit/nocheat/NoCheatConfiguration.java index 310a6c7c..4792efe6 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/NoCheatConfiguration.java +++ b/src/cc/co/evenprime/bukkit/nocheat/NoCheatConfiguration.java @@ -117,16 +117,19 @@ public class NoCheatConfiguration { String[] parts = string.split(" "); for(String s : parts) { + s = s.trim(); if(s.equals("loglow")) - as.add(LogAction.logLow); + as.add(LogAction.loglow); else if(s.equals("logmed")) - as.add(LogAction.logMed); + as.add(LogAction.logmed); else if(s.equals("loghigh")) - as.add(LogAction.logHigh); + as.add(LogAction.loghigh); else if(s.equals("deny")) - as.add(CancelAction.deny); + as.add(CancelAction.cancel); else if(s.equals("reset")) - as.add(CancelAction.reset); + as.add(CancelAction.cancel); + else if(s.equals("cancel")) + as.add(CancelAction.cancel); else if(s.startsWith("custom")) { try { // TODO: Implement Custom Action @@ -136,6 +139,9 @@ public class NoCheatConfiguration { plugin.log(Level.WARNING, "Couldn't parse number of custom action '" + s + "'"); } } + else { + plugin.log(Level.WARNING, "Can't parse action "+ s); + } } diff --git a/src/cc/co/evenprime/bukkit/nocheat/NoCheatData.java b/src/cc/co/evenprime/bukkit/nocheat/NoCheatData.java index 066d37d5..b0b25d39 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/NoCheatData.java +++ b/src/cc/co/evenprime/bukkit/nocheat/NoCheatData.java @@ -1,5 +1,7 @@ package cc.co.evenprime.bukkit.nocheat; +import java.util.logging.Level; + import org.bukkit.Location; import org.bukkit.World; @@ -24,6 +26,7 @@ public class NoCheatData { public Location movingSetBackPoint = null; public Location movingLocation = null; public Runnable movingRunnable = null; + public Level movingHighestLogLevel = null; // WORKAROUND for changed PLAYER_MOVE logic public Location movingTeleportTo = null; @@ -42,5 +45,6 @@ public class NoCheatData { + public NoCheatData() { } } \ No newline at end of file diff --git a/src/cc/co/evenprime/bukkit/nocheat/NoCheatPlugin.java b/src/cc/co/evenprime/bukkit/nocheat/NoCheatPlugin.java index f1530b6a..65744180 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/NoCheatPlugin.java +++ b/src/cc/co/evenprime/bukkit/nocheat/NoCheatPlugin.java @@ -15,6 +15,7 @@ import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.PluginManager; +import cc.co.evenprime.bukkit.nocheat.actions.Action; import cc.co.evenprime.bukkit.nocheat.checks.AirbuildCheck; import cc.co.evenprime.bukkit.nocheat.checks.BedteleportCheck; import cc.co.evenprime.bukkit.nocheat.checks.MovingCheck; @@ -318,4 +319,9 @@ public class NoCheatPlugin extends JavaPlugin { (!bedteleportCheck.isActive() ? bedteleportCheck.getName() + "* " : (hasPermission(p, "nocheat.bedteleport") ? bedteleportCheck.getName() + " " : "")) + (hasPermission(p, "nocheat.notify") ? "notify " : "")); } + + public void handleCustomAction(Action a, Player player) { + // TODO Auto-generated method stub + + } } \ No newline at end of file diff --git a/src/cc/co/evenprime/bukkit/nocheat/actions/Action.java b/src/cc/co/evenprime/bukkit/nocheat/actions/Action.java index 8d49a52e..3eada34d 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/actions/Action.java +++ b/src/cc/co/evenprime/bukkit/nocheat/actions/Action.java @@ -1,5 +1,12 @@ package cc.co.evenprime.bukkit.nocheat.actions; -public interface Action { +public abstract class Action { + public final int firstAfter; + public final boolean repeat; + + public Action(int firstAfter, boolean repeat) { + this.firstAfter = firstAfter; + this.repeat = repeat; + } } \ No newline at end of file diff --git a/src/cc/co/evenprime/bukkit/nocheat/actions/CancelAction.java b/src/cc/co/evenprime/bukkit/nocheat/actions/CancelAction.java index bdef9c6c..849644d9 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/actions/CancelAction.java +++ b/src/cc/co/evenprime/bukkit/nocheat/actions/CancelAction.java @@ -1,9 +1,8 @@ package cc.co.evenprime.bukkit.nocheat.actions; -public class CancelAction implements Action { - - public static final CancelAction deny = new CancelAction(); - public static final CancelAction reset = new CancelAction(); +public class CancelAction extends Action { - private CancelAction() { } + public final static CancelAction cancel = new CancelAction(); + + private CancelAction() { super(1, true); } } diff --git a/src/cc/co/evenprime/bukkit/nocheat/actions/CustomAction.java b/src/cc/co/evenprime/bukkit/nocheat/actions/CustomAction.java new file mode 100644 index 00000000..5395bbbe --- /dev/null +++ b/src/cc/co/evenprime/bukkit/nocheat/actions/CustomAction.java @@ -0,0 +1,12 @@ +package cc.co.evenprime.bukkit.nocheat.actions; + + +public class CustomAction extends Action { + + public final String command; + + public CustomAction(int firstAfter, boolean repeat, String command) { + super(firstAfter, repeat); + this.command = command; + } +} diff --git a/src/cc/co/evenprime/bukkit/nocheat/actions/LogAction.java b/src/cc/co/evenprime/bukkit/nocheat/actions/LogAction.java index 5f0f0b98..17435c96 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/actions/LogAction.java +++ b/src/cc/co/evenprime/bukkit/nocheat/actions/LogAction.java @@ -2,27 +2,18 @@ package cc.co.evenprime.bukkit.nocheat.actions; import java.util.logging.Level; -public class LogAction implements Action { +public class LogAction extends Action { - private final int index; - private final Level level; + public final Level level; - public final static LogAction logLow = new LogAction(0, Level.INFO); - public final static LogAction logMed = new LogAction(1, Level.WARNING); - public final static LogAction logHigh = new LogAction(2, Level.SEVERE); + public final static LogAction loglow = new LogAction(1, false, Level.INFO); + public final static LogAction logmed = new LogAction(1, false, Level.WARNING); + public final static LogAction loghigh = new LogAction(1, false, Level.SEVERE); - public final static LogAction log[] = { logLow, logMed, logHigh }; + public final static LogAction[] log = { loglow, logmed, loghigh }; - private LogAction(int index, Level level) { - this.index = index; + public LogAction(int firstAfter, boolean repeat, Level level) { + super(firstAfter, repeat); this.level = level; } - - public Level getLevel() { - return level; - } - - public int getIndex() { - return index; - } } diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/AirbuildCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/AirbuildCheck.java index 8bc08cca..95d7b5ec 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/AirbuildCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/AirbuildCheck.java @@ -9,6 +9,7 @@ import cc.co.evenprime.bukkit.nocheat.NoCheatData; import cc.co.evenprime.bukkit.nocheat.NoCheatPlugin; import cc.co.evenprime.bukkit.nocheat.actions.Action; import cc.co.evenprime.bukkit.nocheat.actions.CancelAction; +import cc.co.evenprime.bukkit.nocheat.actions.CustomAction; import cc.co.evenprime.bukkit.nocheat.actions.LogAction; @@ -22,9 +23,9 @@ public class AirbuildCheck extends Check { // How should airbuild violations be treated? public final Action actions[][] = { - { LogAction.logLow, CancelAction.deny }, - { LogAction.logMed, CancelAction.deny }, - { LogAction.logHigh, CancelAction.deny } }; + { LogAction.loglow, CancelAction.cancel }, + { LogAction.logmed, CancelAction.cancel }, + { LogAction.loghigh, CancelAction.cancel } }; public final int limits[] = { 1, 3, 10 }; @@ -77,15 +78,31 @@ public class AirbuildCheck extends Check { } } - private void action(Action actions[], BlockPlaceEvent event, boolean log) { + private void action(Action actions[], BlockPlaceEvent event, boolean loggingAllowed) { + if(actions == null) return; + + boolean cancelled = false; + + // Prepare log message if needed + String logMessage = null; + if(loggingAllowed) { + final Location l = event.getBlockPlaced().getLocation(); + logMessage = "Airbuild: "+event.getPlayer().getName()+" tried to place block " + event.getBlockPlaced().getType() + " in the air at " + l.getBlockX() + "," + l.getBlockY() +"," + l.getBlockZ(); + } + + // Execute actions in order for(Action a : actions) { - if(log && a instanceof LogAction) { - final Location l = event.getBlockPlaced().getLocation(); - plugin.log(((LogAction)a).getLevel(), "Airbuild: "+event.getPlayer().getName()+" tried to place block " + event.getBlockPlaced().getType() + " in the air at " + l.getBlockX() + "," + l.getBlockY() +"," + l.getBlockZ()); + if(loggingAllowed && a instanceof LogAction) { + plugin.log(((LogAction)a).level, logMessage); } - else if(a instanceof CancelAction) + else if(!cancelled && a instanceof CancelAction) { event.setCancelled(true); + cancelled = true; + } + else if(a instanceof CustomAction) { + plugin.handleCustomAction(a, event.getPlayer()); + } } } @@ -94,7 +111,7 @@ public class AirbuildCheck extends Check { // Give a summary according to the highest violation level we encountered in that second for(int i = limits.length-1; i >= 0; i--) { if(data.airbuildPerSecond >= limits[i]) { - plugin.log(LogAction.log[i].getLevel(), "Airbuild summary: " +player.getName() + " total violations per second: " + data.airbuildPerSecond); + plugin.log(LogAction.log[i].level, "Airbuild summary: " +player.getName() + " total violations per second: " + data.airbuildPerSecond); break; } } diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/MovingCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/MovingCheck.java index dd25a2db..16b7f28b 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/MovingCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/MovingCheck.java @@ -11,6 +11,7 @@ import cc.co.evenprime.bukkit.nocheat.NoCheatData; import cc.co.evenprime.bukkit.nocheat.NoCheatPlugin; import cc.co.evenprime.bukkit.nocheat.actions.Action; import cc.co.evenprime.bukkit.nocheat.actions.CancelAction; +import cc.co.evenprime.bukkit.nocheat.actions.CustomAction; import cc.co.evenprime.bukkit.nocheat.actions.LogAction; /** @@ -36,17 +37,16 @@ public class MovingCheck extends Check { private final double stepHeight = 0.501D; // Limits - public final double moveLimits[] = { 0.0D, 0.5D, 2.0D }; - + public final double moveLimits[] = { 0.0D, 0.5D, 2.0D }; public final double heightLimits[] = { 0.0D, 0.5D, 2.0D }; public int ticksBeforeSummary = 100; // How should moving violations be treated? public final Action actions[][] = { - { LogAction.logLow, CancelAction.reset }, - { LogAction.logMed, CancelAction.reset }, - { LogAction.logHigh, CancelAction.reset } }; + { LogAction.loglow, CancelAction.cancel }, + { LogAction.logmed, CancelAction.cancel }, + { LogAction.loghigh, CancelAction.cancel } }; private static final double magic = 0.30000001192092896D; private static final double magic2 = 0.69999998807907103D; @@ -158,14 +158,13 @@ public class MovingCheck extends Check { // Get the player-specific data final NoCheatData data = plugin.getPlayerData(event.getPlayer()); - + // Get the two locations of the event final Location to = event.getTo(); - // WORKAROUND for changed PLAYER_MOVE logic final Location from = data.movingTeleportTo == null ? event.getFrom() : data.movingTeleportTo; data.movingTeleportTo = null; - + // Notice to myself: How world changes with e.g. command /world work: // 1. TeleportEvent from the players current position to another position in the _same_ world // 2. MoveEvent(s) (yes, multiple events can be triggered) from that position in the _new_ world @@ -208,17 +207,16 @@ public class MovingCheck extends Check { // The actual movingCheck starts here // First check the distance the player has moved horizontally - double xDistance = from.getX()-to.getX(); - double zDistance = from.getZ()-to.getZ(); + double xDistance = Math.abs(from.getX()-to.getX()); + double zDistance = Math.abs(from.getZ()-to.getZ()); + double combined = Math.sqrt((xDistance*xDistance + zDistance*zDistance)); + // If the target is a bed and distance not too big, allow it - if(to.getWorld().getBlockTypeIdAt(to) == Material.BED_BLOCK.getId() && xDistance < 8.0D && zDistance < 8.0D) { + if(to.getWorld().getBlockTypeIdAt(to) == Material.BED_BLOCK.getId() && combined < 8.0D) { return; // players are allowed to "teleport" into a bed over "short" distances } - // Calculate the horizontal distance - double combined = Math.sqrt((xDistance*xDistance + zDistance*zDistance)) - 0.6D ; - // Give additional movement based on velocity (not too precise, but still better than false positives) Vector v = event.getPlayer().getVelocity(); @@ -226,23 +224,8 @@ public class MovingCheck extends Check { double tmp = Math.abs(v.getX()*5D) + Math.abs(v.getZ()*5D); data.movingHorizFreedom = tmp > data.movingHorizFreedom * 0.9D ? tmp : data.movingHorizFreedom * 0.9D; - // subtract the additional freedom - combined -= data.movingHorizFreedom; - // Violation level - int vl1 = -1; - - // How far are we off? - if(combined > moveLimits[2]) { - vl1 = max(vl1, 2); - } - else if(combined > moveLimits[1]) { - vl1 = max(vl1, 1); - } - else if(combined > moveLimits[0]) { - vl1 = max(vl1, 0); - } - + int vl1 = limitCheck(combined - data.movingHorizFreedom - 0.6D, moveLimits); // pre-calculate boundary values that are needed multiple times in the following checks // the array each contains [lowerX, higherX, Y, lowerZ, higherZ] @@ -253,20 +236,18 @@ public class MovingCheck extends Check { final boolean onGroundFrom = playerIsOnGround(from.getWorld(), fromValues, from); final boolean onGroundTo = playerIsOnGround(to.getWorld(), toValues, to); - // Handle 4 distinct cases: Walk, Jump, Land, Fly - int vl2 = -1; // A halfway lag-resistant method of allowing vertical acceleration without allowing blatant cheating - + // FACT: Minecraft server sends player "velocity" to the client and lets the client calculate the movement // PROBLEM: There may be an arbitrary amount of other move events between the server sending the data // and the client accepting it/reacting to it. The server can't know when the client starts to // consider the sent "velocity" in its movement. // SOLUTION: Give the client at least 10 events after sending "velocity" to actually use the velocity for // its movement, plus additional events if the "velocity" was big and can cause longer flights - + // The server sent the player a "velocity" a short time ago if(v.getY() > 0.0D) { if(data.movingVertFreedomCounter < 10) @@ -275,8 +256,8 @@ public class MovingCheck extends Check { // Be generous with the height limit for the client data.movingVertFreedom += v.getY()*3D; - // Set a top limit for how many events a client has to "consume" the sent velocity - if(data.movingVertFreedomCounter < 30) + // Set a top limit for how many events a client has to "consume" the added freedom + if(data.movingVertFreedomCounter < 40) data.movingVertFreedomCounter++; } // If the server no longer has a positive velocity, start consuming the event counter for this client @@ -291,117 +272,99 @@ public class MovingCheck extends Check { double limit = data.movingVertFreedom; - // Walk - if(onGroundFrom && onGroundTo) + Location newSetBack = null; + + // Walk or start Jump + if(onGroundFrom) { limit += jumpHeight; double distance = to.getY() - from.getY(); - vl2 = heightLimitCheck(limit, distance); + vl2 = limitCheck(distance - limit, heightLimits); - if(vl1 < 0 && vl2 < 0) + if(vl2 < 0) { // reset jumping - data.movingJumpPhase = 0; - data.movingSetBackPoint = from.clone(); + if(onGroundTo) + data.movingJumpPhase = 0; // Walk + else + data.movingJumpPhase = 1; // Jump + + newSetBack = from.clone(); } } - // Jump - else if(onGroundFrom && !onGroundTo) - { - limit += jumpHeight; - double distance = to.getY() - from.getY(); - - // Check if player isn't jumping too high - vl2 = heightLimitCheck(limit, distance); - - if(vl1 < 0 && vl2 < 0) { - // Setup next phase of the jump - data.movingJumpPhase = 1; - data.movingSetBackPoint = from.clone(); - } - } - // Land - else if(!onGroundFrom && onGroundTo) + // Land or Fly/Fall + else { Location l = data.movingSetBackPoint == null ? from : data.movingSetBackPoint; - if(data.movingJumpPhase > jumpingLimit) - limit += jumpHeight + stepHeight - (data.movingJumpPhase-jumpingLimit) * 0.2D; - else limit += jumpHeight; - - double distance = to.getY() - l.getY(); - - // Check if player isn't jumping too high - vl2 = heightLimitCheck(limit, distance); - - if(vl1 < 0 && vl2 < 0) { - data.movingJumpPhase = 0; // He is on ground now, so reset the jump - data.movingSetBackPoint = to.clone(); - } - } - // Player is moving through air (during jumping, falling) - else { - Location l = data.movingSetBackPoint == null ? from : data.movingSetBackPoint; - if(data.movingJumpPhase > jumpingLimit) limit += jumpHeight - (data.movingJumpPhase-jumpingLimit) * 0.2D; else limit += jumpHeight; + if(onGroundTo) limit += stepHeight; + double distance = to.getY() - l.getY(); // Check if player isn't jumping too high - vl2 = heightLimitCheck(limit, distance); + vl2 = limitCheck(distance - limit, heightLimits); - if(vl1 < 0 && vl2 < 0) { - data.movingJumpPhase++; // Enter next phase of the flight - // Setback point stays the same. If we don't have one, take the "from" location as a setback point for now - if(data.movingSetBackPoint == null) { - data.movingSetBackPoint = from.clone(); + if(vl2 < 0) { + if(onGroundTo) { // Land + data.movingJumpPhase = 0; // He is on ground now, so reset the jump + newSetBack = to.clone(); + } + else { // Fly + data.movingJumpPhase++; // Enter next phase of the flight + // If we have no setback point, create one now + if(data.movingSetBackPoint == null) { + newSetBack = from.clone(); + } } } } int vl = max(vl1, vl2); + + + if(vl < 0) { + data.movingSetBackPoint = newSetBack == null ? data.movingSetBackPoint : newSetBack; + } + + // If we haven't already got a setback point by now, make this location the new setback point + if(data.movingSetBackPoint == null) { + data.movingSetBackPoint = event.getFrom().clone(); + } + if(vl >= 0) { - final Player p = event.getPlayer(); - final NoCheatData d = data; + setupSummaryTask(event.getPlayer(), data); - // Setup task to display summary later - if(data.movingRunnable == null) { - data.movingRunnable = new Runnable() { - - @Override - public void run() { - summary(p, d); - // deleting its own reference - d.movingRunnable = null; - } - }; - - // Give a summary in x ticks. 20 ticks ~ 1 second - plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, data.movingRunnable, ticksBeforeSummary); - } - - // If we haven't already got a setback point, make this location the new setback point - if(data.movingSetBackPoint == null) { - data.movingSetBackPoint = event.getFrom().clone(); - } - - Action action[] = null; - boolean log = true; - - // Find out with what actions to treat the violation(s) - if(data.movingViolationsInARow[vl] > 0) log = false; // only log the first violation of that level + boolean log = !(data.movingViolationsInARow[vl] > 0); data.movingViolationsInARow[vl]++; - action = actions[vl]; - action(event, event.getPlayer(), from, to, action, log); + action(event, event.getPlayer(), from, to, actions[vl], log, data); } } + private void setupSummaryTask(final Player player, final NoCheatData data) { + // Setup task to display summary later + if(data.movingRunnable == null) { + data.movingRunnable = new Runnable() { + @Override + public void run() { + summary(player, data); + // deleting its own reference + data.movingRunnable = null; + } + }; + + // Give a summary in x ticks. 20 ticks ~ 1 second + plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, data.movingRunnable, ticksBeforeSummary); + } + + } public void teleported(PlayerMoveEvent event) { NoCheatData data = plugin.getPlayerData(event.getPlayer()); @@ -428,43 +391,43 @@ public class MovingCheck extends Check { * @param event * @param action */ - private void action(PlayerMoveEvent event, Player player, Location from, Location to, Action[] actions, boolean log) { + private void action(PlayerMoveEvent event, Player player, Location from, Location to, Action[] actions, boolean loggingAllowed, NoCheatData data) { if(actions == null) return; + boolean cancelled = false; + + // prepare log message if neccessary + String logMessage = null; + + if(loggingAllowed) { + logMessage = "Moving violation: "+player.getName()+" from " + String.format("%s (%.5f, %.5f, %.5f) to %s (%.5f, %.5f, %.5f)", from.getWorld().getName(), from.getX(), from.getY(), from.getZ(), to.getWorld().getName(), to.getX(), to.getY(), to.getZ()); + } for(Action a : actions) { - if(a instanceof LogAction) - plugin.log(((LogAction)a).getLevel(), "Moving violation: "+player.getName()+" from " + String.format("%s (%.5f, %.5f, %.5f) to %s (%.5f, %.5f, %.5f)", from.getWorld().getName(), from.getX(), from.getY(), from.getZ(), to.getWorld().getName(), to.getX(), to.getY(), to.getZ())); - else if(a.equals(CancelAction.reset)) + if(a instanceof LogAction) { + plugin.log(((LogAction)a).level, logMessage); + data.movingHighestLogLevel = ((LogAction)a).level.intValue() > data.movingHighestLogLevel.intValue() ? ((LogAction)a).level : data.movingHighestLogLevel; + } + else if(!cancelled && a instanceof CancelAction) { resetPlayer(event, from); + cancelled = true; + } + else if(a instanceof CustomAction) + plugin.handleCustomAction(a, player); } } private void summary(Player p, NoCheatData data) { - LogAction log = null; - String logString = "Moving summary of last ~" + (ticksBeforeSummary/20) + " seconds: "+p.getName() + " total Violations: ("+ data.movingViolationsInARow[0] + "," + data.movingViolationsInARow[1] + "," + data.movingViolationsInARow[2] + ")"; - // Find out the biggest applicable log level - for(int i = 0; i < data.movingViolationsInARow.length; i++) { - if(data.movingViolationsInARow[i] > 0) - for(Action a : actions[i]) - if(a instanceof LogAction) - if(log == null || ((LogAction)a).getIndex() > log.getIndex()) - log = (LogAction)a; - data.movingViolationsInARow[i] = 0; - } - if(log != null) - plugin.log(log.getLevel(), logString); + plugin.log(data.movingHighestLogLevel, logString); } - private int heightLimitCheck(double limit, double value) { + private int limitCheck(double value, double limits[]) { - double offset = value - limit; - - for(int i = heightLimits.length - 1; i >= 0; i--) { - if(offset > heightLimits[i]) { + for(int i = limits.length - 1; i >= 0; i--) { + if(value > limits[i]) { return i; } } @@ -517,27 +480,15 @@ public class MovingCheck extends Check { /** - * Check the four edges of the player's approximated Bounding Box for blocks or ladders, - * at his own height (values[2]) and below his feet (values[2]-1). Also, check at his "head" - * for ladders. - * - * If there is one, the player is considered as standing on it/hanging to it. - * - * Not perfect at all and will produce some false negatives. Probably will be refined - * later. + * Check if certain coordinates are considered "on ground" or in air * * @param w The world the coordinates belong to * @param values The coordinates [lowerX, higherX, Y, lowerZ, higherZ] + * @param l The location that was used for calculation of "values" * @return */ private static boolean playerIsOnGround(World w, int values[], Location l) { - // Completely revamped collision detection - // What it does: - // Check the blocks below the player. If they aren't not solid (sic!) and the blocks directly above - // them aren't solid, The player is considered to be standing on the lower block - // Plus the player can hang onto a ladder that is one field above him - // Check the four borders of the players hitbox for something he could be standing on if(types[w.getBlockTypeIdAt(values[0], values[2]-1, values[3])] != BlockType.NONSOLID || types[w.getBlockTypeIdAt(values[1], values[2]-1, values[3])] != BlockType.NONSOLID || @@ -548,7 +499,7 @@ public class MovingCheck extends Check { else if(types[w.getBlockTypeIdAt(l.getBlockX(), l.getBlockY(), l.getBlockZ())] == BlockType.LADDER || types[w.getBlockTypeIdAt(l.getBlockX(), l.getBlockY()+1, l.getBlockZ())] == BlockType.LADDER) return true; - // check if he is standing "in" an block that's potentially solid (we give him the benefit of a doubt and see that as a legit move) + // check if he is standing "in" a block that's potentially solid (we give him the benefit of a doubt and see that as a legit move) // If it is not legit, the MC server already has a safeguard against that (You'll get "xy moved wrongly" on the console in that case) else if(types[w.getBlockTypeIdAt(values[0], values[2], values[3])] != BlockType.NONSOLID || types[w.getBlockTypeIdAt(values[1], values[2], values[3])] != BlockType.NONSOLID|| @@ -562,7 +513,7 @@ public class MovingCheck extends Check { types[w.getBlockTypeIdAt(values[0], values[2]+1, values[4])] != BlockType.NONSOLID || types[w.getBlockTypeIdAt(values[1], values[2]+1, values[4])] != BlockType.NONSOLID) return true; - // Allow using a bug called "water elevator" + // Allow using a bug called "water elevator" by checking northwest of the players location for liquids else if(types[w.getBlockTypeIdAt(values[0]+1, values[2]-1, values[3]+1)] == BlockType.LIQUID || types[w.getBlockTypeIdAt(values[0]+1, values[2], values[3]+1)] == BlockType.LIQUID || types[w.getBlockTypeIdAt(values[0]+1, values[2]+1, values[3]+1)] == BlockType.LIQUID || diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/SpeedhackCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/SpeedhackCheck.java index 1262f7c8..2a2c3c70 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/SpeedhackCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/SpeedhackCheck.java @@ -7,6 +7,7 @@ import cc.co.evenprime.bukkit.nocheat.NoCheatData; import cc.co.evenprime.bukkit.nocheat.NoCheatPlugin; import cc.co.evenprime.bukkit.nocheat.actions.Action; import cc.co.evenprime.bukkit.nocheat.actions.CancelAction; +import cc.co.evenprime.bukkit.nocheat.actions.CustomAction; import cc.co.evenprime.bukkit.nocheat.actions.LogAction; /** @@ -30,9 +31,9 @@ public class SpeedhackCheck extends Check { // How should speedhack violations be treated? public Action actions[][] = { - { LogAction.logLow, CancelAction.reset }, - { LogAction.logMed, CancelAction.reset }, - { LogAction.logHigh, CancelAction.reset } }; + { LogAction.loglow, CancelAction.cancel }, + { LogAction.logmed, CancelAction.cancel }, + { LogAction.loghigh, CancelAction.cancel } }; public void check(PlayerMoveEvent event) { @@ -100,11 +101,15 @@ public class SpeedhackCheck extends Check { if(actions == null) return; + String logMessage = event.getPlayer().getName()+" sent "+ data.speedhackEventsSinceLastCheck + " move events, but only "+limits[0]+ " were allowed. Speedhack?"; + for(Action a : actions) { if(a instanceof LogAction) - plugin.log(((LogAction)a).getLevel(), event.getPlayer().getName()+" sent "+ data.speedhackEventsSinceLastCheck + " move events, but only "+limits[0]+ " were allowed. Speedhack?"); - else if(a.equals(CancelAction.reset)) + plugin.log(((LogAction)a).level, logMessage); + else if(a instanceof CancelAction) resetPlayer(event, data); + else if(a instanceof CustomAction) + plugin.handleCustomAction(a, event.getPlayer()); } }