diff --git a/src/cc/co/evenprime/bukkit/nocheat/NoCheat.java b/src/cc/co/evenprime/bukkit/nocheat/NoCheat.java index f1e77ed8..c0df5dda 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/NoCheat.java +++ b/src/cc/co/evenprime/bukkit/nocheat/NoCheat.java @@ -86,7 +86,7 @@ public class NoCheat extends JavaPlugin implements Listener { eventManagers = new ArrayList(8); // Big enough // Then set up the event listeners eventManagers.add(new MovingCheckListener(this)); - eventManagers.add(new WorkaroundsListener(this)); + eventManagers.add(new WorkaroundsListener()); eventManagers.add(new ChatCheckListener(this)); eventManagers.add(new BlockBreakCheckListener(this)); eventManagers.add(new BlockPlaceCheckListener(this)); diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/Check.java b/src/cc/co/evenprime/bukkit/nocheat/checks/Check.java index 09319c5b..32ea2b78 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/Check.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/Check.java @@ -17,6 +17,10 @@ import cc.co.evenprime.bukkit.nocheat.actions.types.SpecialAction; import cc.co.evenprime.bukkit.nocheat.config.ConfigurationCacheStore; import cc.co.evenprime.bukkit.nocheat.data.Statistics.Id; +/** + * The abstract Check class, providing some basic functionality + * + */ public abstract class Check { private final String name; @@ -41,13 +45,18 @@ public abstract class Check { boolean special = false; + // Get the to be executed actions Action[] actions = actionList.getActions(violationLevel); final long time = System.currentTimeMillis() / 1000L; + + // The configuration will be needed too final ConfigurationCacheStore cc = player.getConfigurationStore(); for(Action ac : actions) { if(player.getExecutionHistory().executeAction(groupId, ac, time)) { + // The executionHistory said it really is time to execute the + // action, find out what it is and do what is needed if(ac instanceof LogAction && !player.hasPermission(actionList.permissionSilent)) { executeLogAction((LogAction) ac, this, player, cc); } else if(ac instanceof SpecialAction) { @@ -79,6 +88,7 @@ public abstract class Check { if(!cc.logging.active) return; + // Fire one of our custom "Log" Events Bukkit.getServer().getPluginManager().callEvent(new NoCheatLogEvent(cc.logging.prefix, l.getLogMessage(player, check), cc.logging.toConsole && l.toConsole(), cc.logging.toChat && l.toChat(), cc.logging.toFile && l.toFile())); } diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/CheckUtil.java b/src/cc/co/evenprime/bukkit/nocheat/checks/CheckUtil.java index c292618b..ab5064bf 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/CheckUtil.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/CheckUtil.java @@ -12,7 +12,8 @@ import cc.co.evenprime.bukkit.nocheat.NoCheatPlayer; import cc.co.evenprime.bukkit.nocheat.data.PreciseLocation; /** - * Some stuff that's used by different checks + * Some stuff that's used by different checks or just too complex to keep + * in other places * */ public class CheckUtil { @@ -85,10 +86,11 @@ public class CheckUtil { // All fences are solid - fences are treated specially due // to being 1.5 blocks high - private static final int FENCE = 16 | SOLID | NONSOLID; // 0x00010010 + private static final int FENCE = 16 | SOLID | NONSOLID; // 0x00010011 private static final int INGROUND = 128; private static final int ONGROUND = 256; + // Until I can think of a better way to determine if a block is solid or // not, this is what I'll do private static final int types[]; @@ -168,6 +170,8 @@ public class CheckUtil { * } * } */ + + // We need to know what is considered food for the instanteat check foods.add(Material.APPLE); foods.add(Material.BREAD); foods.add(Material.COOKED_BEEF); @@ -202,7 +206,7 @@ public class CheckUtil { final int lowerX = lowerBorder(location.x); final int upperX = upperBorder(location.x); - final int Y = (int) Math.floor(location.y); + final int Y = (int) location.y; final int lowerZ = lowerBorder(location.z); final int upperZ = upperBorder(location.z); diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/WorkaroundsListener.java b/src/cc/co/evenprime/bukkit/nocheat/checks/WorkaroundsListener.java index 90be8703..0e92610b 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/WorkaroundsListener.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/WorkaroundsListener.java @@ -8,7 +8,6 @@ import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerToggleSprintEvent; import cc.co.evenprime.bukkit.nocheat.EventManager; -import cc.co.evenprime.bukkit.nocheat.NoCheat; import cc.co.evenprime.bukkit.nocheat.config.ConfigurationCacheStore; /** @@ -18,12 +17,7 @@ import cc.co.evenprime.bukkit.nocheat.config.ConfigurationCacheStore; */ public class WorkaroundsListener implements Listener, EventManager { - //private final NoCheat plugin; - - public WorkaroundsListener(NoCheat plugin) { - - //this.plugin = plugin; - } + public WorkaroundsListener() {} @EventHandler(priority = EventPriority.HIGHEST) public void playerMove(final PlayerMoveEvent event) { @@ -39,12 +33,14 @@ public class WorkaroundsListener implements Listener, EventManager { @EventHandler(priority = EventPriority.HIGHEST) public void toggleSprint(final PlayerToggleSprintEvent event) { + // Some plugins cancel "sprinting", which makes no sense at all because + // it doesn't stop people from sprinting and rewards them by reducing + // their hunger bar as if they were walking instead of sprinting if(event.isCancelled() && event.isSprinting()) { event.setCancelled(false); } } - @Override public List getActiveChecks(ConfigurationCacheStore cc) { return Collections.emptyList(); } diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/moving/FlyingCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/moving/FlyingCheck.java index 9fc417e7..56d8e2a9 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/moving/FlyingCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/moving/FlyingCheck.java @@ -19,23 +19,29 @@ public class FlyingCheck extends MovingCheck { super(plugin, "moving.flying"); } + // Determined by trial and error, the flying movement speed of the creative + // mode private static final double creativeSpeed = 0.60D; public PreciseLocation check(NoCheatPlayer player, MovingData data, MovingConfig ccmoving) { + // The setBack is the location that players may get teleported to when + // they fail the check final PreciseLocation setBack = data.runflySetBackPoint; + final PreciseLocation from = data.from; final PreciseLocation to = data.to; + // If we have no setback, define one now if(!setBack.isSet()) { setBack.set(from); } + // Used to store the location where the player gets teleported to PreciseLocation newToLocation = null; - // Before doing anything, do a basic height check - // This is silent for now, will log messages later - // probably + // Before doing anything, do a basic height check to determine if + // players are flying too high if(to.y - data.vertFreedom > ccmoving.flyingHeightLimit) { newToLocation = new PreciseLocation(); newToLocation.set(setBack); @@ -43,33 +49,36 @@ public class FlyingCheck extends MovingCheck { return newToLocation; } - final double yDistance = to.y - from.y; - // Calculate some distances + final double yDistance = to.y - from.y; final double xDistance = to.x - from.x; final double zDistance = to.z - from.z; + + // How far did the player move horizontally final double horizontalDistance = Math.sqrt((xDistance * xDistance + zDistance * zDistance)); double resultHoriz = 0; double resultVert = 0; double result = 0; - // In case of creative gamemode, give at least 0.60 speed limit - // horizontal + // In case of creative game mode give at least 0.60 speed limit horizontal double speedLimitHorizontal = player.isCreative() ? Math.max(creativeSpeed, ccmoving.flyingSpeedLimitHorizontal) : ccmoving.flyingSpeedLimitHorizontal; + // If the player is affected by potion of swiftness speedLimitHorizontal *= player.getSpeedAmplifier(); + // Finally, determine how far the player went beyond the set limits resultHoriz = Math.max(0.0D, horizontalDistance - data.horizFreedom - speedLimitHorizontal); boolean sprinting = player.isSprinting(); data.bunnyhopdelay--; - // Did he go too far? if(resultHoriz > 0 && sprinting) { // Try to treat it as a the "bunnyhop" problem + // The bunnyhop problem is that landing and immediatly jumping + // again leads to a player moving almost twice as far in that step if(data.bunnyhopdelay <= 0 && resultHoriz < 0.4D) { data.bunnyhopdelay = 9; resultHoriz = 0; @@ -78,6 +87,9 @@ public class FlyingCheck extends MovingCheck { resultHoriz *= 100; + // Is the player affected by the "jumping" potion + // This is really just a very, very crude estimation and far from + // reality double jumpAmplifier = player.getJumpAmplifier(); if(jumpAmplifier > data.lastJumpAmplifier) { data.lastJumpAmplifier = jumpAmplifier; @@ -89,14 +101,15 @@ public class FlyingCheck extends MovingCheck { data.lastJumpAmplifier--; } - // super simple, just check distance compared to max distance + // super simple, just check distance compared to max distance vertical resultVert = Math.max(0.0D, yDistance - data.vertFreedom - speedLimitVertical) * 100; result = resultHoriz + resultVert; + // The player went to far, either horizontal or vertical if(result > 0) { - // Increment violation counter + // Increment violation counter and statistics data.runflyVL += result; if(resultHoriz > 0) { incrementStatistics(player, Id.MOV_RUNNING, resultHoriz); @@ -106,6 +119,8 @@ public class FlyingCheck extends MovingCheck { incrementStatistics(player, Id.MOV_FLYING, resultVert); } + // Execute whatever actions are associated with this check and the + // violation level and find out if we should cancel the event boolean cancel = executeActions(player, ccmoving.flyingActions, data.runflyVL); // Was one of the actions a cancel? Then really do it @@ -114,10 +129,10 @@ public class FlyingCheck extends MovingCheck { } } - // Slowly reduce the level with each event + // Slowly reduce the violation level with each event data.runflyVL *= 0.97; - // Some other cleanup 'n' stuff + // If the player did not get cancelled, define a new setback point if(newToLocation == null) { setBack.set(to); } @@ -125,10 +140,11 @@ public class FlyingCheck extends MovingCheck { return newToLocation; } + @Override public String getParameter(ParameterName wildcard, NoCheatPlayer player) { if(wildcard == ParameterName.VIOLATIONS) - return String.format(Locale.US, "%d", (int) getData(player.getDataStore()).runflyVL); + return String.format(Locale.US, "%d", (int) getData(player).runflyVL); else return super.getParameter(wildcard, player); } diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/moving/MorePacketsCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/moving/MorePacketsCheck.java index 5dec3fc6..ae5d7ac1 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/moving/MorePacketsCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/moving/MorePacketsCheck.java @@ -19,6 +19,7 @@ import cc.co.evenprime.bukkit.nocheat.data.Statistics.Id; */ public class MorePacketsCheck extends MovingCheck { + // 20 would be for perfect internet connections, 22 is good enough private final static int packetsPerTimeframe = 22; public MorePacketsCheck(NoCheat plugin) { @@ -55,6 +56,8 @@ public class MorePacketsCheck extends MovingCheck { data.packets = -data.morePacketsBuffer; + // Execute whatever actions are associated with this check and the + // violation level and find out if we should cancel the event final boolean cancel = executeActions(player, cc.morePacketsActions, data.morePacketsVL); if(cancel) @@ -100,9 +103,9 @@ public class MorePacketsCheck extends MovingCheck { public String getParameter(ParameterName wildcard, NoCheatPlayer player) { if(wildcard == ParameterName.VIOLATIONS) - return String.format(Locale.US, "%d", (int) getData(player.getDataStore()).morePacketsVL); + return String.format(Locale.US, "%d", (int) getData(player).morePacketsVL); else if(wildcard == ParameterName.PACKETS) - return String.format(Locale.US, "%d", (int) getData(player.getDataStore()).packets); + return String.format(Locale.US, "%d", (int) getData(player).packets); else return super.getParameter(wildcard, player); } diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/moving/MovingCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/moving/MovingCheck.java index 0878a01b..2d0caeee 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/moving/MovingCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/moving/MovingCheck.java @@ -9,6 +9,10 @@ import cc.co.evenprime.bukkit.nocheat.config.ConfigurationCacheStore; import cc.co.evenprime.bukkit.nocheat.data.DataStore; import cc.co.evenprime.bukkit.nocheat.data.PreciseLocation; +/** + * Abstract base class for Moving checks, provides some convenience + * methods for access to data and config that's relevant to this checktype + */ public abstract class MovingCheck extends Check { private static final String id = "moving"; @@ -21,21 +25,29 @@ public abstract class MovingCheck extends Check { public String getParameter(ParameterName wildcard, NoCheatPlayer player) { if(wildcard == ParameterName.LOCATION) { - PreciseLocation from = getData(player.getDataStore()).from; + PreciseLocation from = getData(player).from; return String.format(Locale.US, "%.2f,%.2f,%.2f", from.x, from.y, from.z); } else if(wildcard == ParameterName.MOVEDISTANCE) { - PreciseLocation from = getData(player.getDataStore()).from; - PreciseLocation to = getData(player.getDataStore()).to; + PreciseLocation from = getData(player).from; + PreciseLocation to = getData(player).to; return String.format(Locale.US, "%.2f,%.2f,%.2f", to.x - from.x, to.y - from.y, to.z - from.z); } else if(wildcard == ParameterName.LOCATION_TO) { - PreciseLocation to = getData(player.getDataStore()).to; + PreciseLocation to = getData(player).to; return String.format(Locale.US, "%.2f,%.2f,%.2f", to.x, to.y, to.z); } else return super.getParameter(wildcard, player); } - public static MovingData getData(DataStore base) { + /** + * Get the "MovingData" object that belongs to the player. Will ensure + * that such a object exists and if not, create one + * + * @param player + * @return + */ + public static MovingData getData(NoCheatPlayer player) { + DataStore base = player.getDataStore(); MovingData data = base.get(id); if(data == null) { data = new MovingData(); @@ -44,6 +56,17 @@ public abstract class MovingCheck extends Check { return data; } + /** + * Get the MovingConfig object that belongs to the world that the player + * currently resides in. + * + * @param player + * @return + */ + public static MovingConfig getConfig(NoCheatPlayer player) { + return getConfig(player.getConfigurationStore()); + } + public static MovingConfig getConfig(ConfigurationCacheStore cache) { MovingConfig config = cache.get(id); if(config == null) { diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/moving/MovingCheckListener.java b/src/cc/co/evenprime/bukkit/nocheat/checks/moving/MovingCheckListener.java index 02656825..797dd06d 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/moving/MovingCheckListener.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/moving/MovingCheckListener.java @@ -24,10 +24,8 @@ import cc.co.evenprime.bukkit.nocheat.config.Permissions; import cc.co.evenprime.bukkit.nocheat.data.PreciseLocation; /** - * The only place that listens to and modifies player_move events if necessary - * - * Get the event, decide which checks should work on it and in what order, - * evaluate the check results and decide what to + * Central location to listen to events that are + * relevant for the moving checks * */ public class MovingCheckListener implements Listener, EventManager { @@ -56,7 +54,7 @@ public class MovingCheckListener implements Listener, EventManager { * was already on top of that block and should be allowed to stay * there * - * @param event + * @param event The BlockPlaceEvent */ @EventHandler(priority = EventPriority.MONITOR) public void blockPlace(final BlockPlaceEvent event) { @@ -66,7 +64,7 @@ public class MovingCheckListener implements Listener, EventManager { return; final NoCheatPlayer player = plugin.getPlayer(event.getPlayer()); - final MovingConfig config = MovingCheck.getConfig(player.getConfigurationStore()); + final MovingConfig config = MovingCheck.getConfig(player); // If the player is allowed to fly anyway, the workaround is not needed // It's kind of expensive (looking up block types) therefore it makes @@ -76,7 +74,7 @@ public class MovingCheckListener implements Listener, EventManager { } // Get the player-specific stored data that applies here - final MovingData data = MovingCheck.getData(player.getDataStore()); + final MovingData data = MovingCheck.getData(player); final Block block = event.getBlockPlaced(); @@ -109,15 +107,15 @@ public class MovingCheckListener implements Listener, EventManager { * it was NoCheat or another plugin. If it was NoCheat, the target * location should match the "data.teleportTo" value. * - * On teleports, reset some movement related data + * On teleports, reset some movement related data that gets invalid * - * @param event + * @param event The PlayerTeleportEvent */ @EventHandler(priority = EventPriority.HIGHEST) public void teleport(final PlayerTeleportEvent event) { NoCheatPlayer player = plugin.getPlayer(event.getPlayer()); - final MovingData data = MovingCheck.getData(player.getDataStore()); + final MovingData data = MovingCheck.getData(player); // If it was a teleport initialized by NoCheat, do it anyway // even if another plugin said "no" @@ -141,14 +139,15 @@ public class MovingCheckListener implements Listener, EventManager { /** * Just for security, if a player switches between worlds, reset the - * runfly and morepackets checks. + * runfly and morepackets checks data, because it is definitely invalid + * now * - * @param event + * @param event The PlayerChangedWorldEvent */ @EventHandler(priority = EventPriority.MONITOR) public void worldChange(final PlayerChangedWorldEvent event) { // Maybe this helps with people teleporting through multiverse portals having problems? - final MovingData data = MovingCheck.getData(plugin.getPlayer(event.getPlayer()).getDataStore()); + final MovingData data = MovingCheck.getData(plugin.getPlayer(event.getPlayer())); data.teleportTo.reset(); data.clearRunFlyData(); data.clearMorePacketsData(); @@ -162,7 +161,7 @@ public class MovingCheckListener implements Listener, EventManager { */ @EventHandler(priority = EventPriority.MONITOR) public void portal(final PlayerPortalEvent event) { - final MovingData data = MovingCheck.getData(plugin.getPlayer(event.getPlayer()).getDataStore()); + final MovingData data = MovingCheck.getData(plugin.getPlayer(event.getPlayer())); data.clearMorePacketsData(); data.clearRunFlyData(); } @@ -175,7 +174,7 @@ public class MovingCheckListener implements Listener, EventManager { */ @EventHandler(priority = EventPriority.MONITOR) public void respawn(final PlayerRespawnEvent event) { - final MovingData data = MovingCheck.getData(plugin.getPlayer(event.getPlayer()).getDataStore()); + final MovingData data = MovingCheck.getData(plugin.getPlayer(event.getPlayer())); data.clearMorePacketsData(); data.clearRunFlyData(); } @@ -184,22 +183,26 @@ public class MovingCheckListener implements Listener, EventManager { * When a player moves, he will be checked for various * suspicious behaviour. * - * @param event + * @param event The PlayerMoveEvent */ @EventHandler(priority = EventPriority.LOWEST) public void move(final PlayerMoveEvent event) { + // Don't care for vehicles if(event.isCancelled() || event.getPlayer().isInsideVehicle()) return; + // Don't care for movements that are very high distance or to another + // world (such that it is very likely the event data was modified by + // another plugin before we got it) if(!event.getFrom().getWorld().equals(event.getTo().getWorld()) || event.getFrom().distanceSquared(event.getTo()) > 400) { return; } - + final NoCheatPlayer player = plugin.getPlayer(event.getPlayer()); - final MovingConfig cc = MovingCheck.getConfig(player.getConfigurationStore()); - final MovingData data = MovingCheck.getData(player.getDataStore()); + final MovingConfig cc = MovingCheck.getConfig(player); + final MovingData data = MovingCheck.getData(player); // Advance various counters and values that change per movement // tick. They are needed to decide on how fast a player may @@ -210,9 +213,6 @@ public class MovingCheckListener implements Listener, EventManager { data.from.set(event.getFrom()); final Location to = event.getTo(); data.to.set(to); - - - PreciseLocation newTo = null; @@ -240,7 +240,8 @@ public class MovingCheckListener implements Listener, EventManager { // Did one of the check(s) decide we need a new "to"-location? if(newTo != null) { // Compose a new location based on coordinates of "newTo" and - // viewing direction of "event.getTo()" + // viewing direction of "event.getTo()" to allow the player to + // look somewhere else despite getting pulled back by NoCheat event.setTo(new Location(player.getPlayer().getWorld(), newTo.x, newTo.y, newTo.z, to.getYaw(), to.getPitch())); // remember where we send the player to @@ -279,16 +280,16 @@ public class MovingCheckListener implements Listener, EventManager { /** * Player got a velocity packet. The server can't keep track * of actual velocity values (by design), so we have to try - * and do that ourselves. + * and do that ourselves. Very rough estimates. * - * @param event + * @param event The PlayerVelocityEvent */ @EventHandler(priority = EventPriority.MONITOR) public void velocity(final PlayerVelocityEvent event) { if(event.isCancelled()) return; - final MovingData data = MovingCheck.getData(plugin.getPlayer(event.getPlayer()).getDataStore()); + final MovingData data = MovingCheck.getData(plugin.getPlayer(event.getPlayer())); final Vector v = event.getVelocity(); diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/moving/MovingData.java b/src/cc/co/evenprime/bukkit/nocheat/checks/moving/MovingData.java index 021885a3..3299e55d 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/moving/MovingData.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/moving/MovingData.java @@ -9,45 +9,61 @@ import cc.co.evenprime.bukkit.nocheat.data.Statistics.Id; */ public class MovingData implements DataItem { + // Keep track of the violation levels of the checks public double runflyVL; public double nofallVL; public double morePacketsVL; + // Count how long a player is in the air public int jumpPhase; + + // Remember how big the players last JumpAmplifier (potion effect) was public double lastJumpAmplifier; + + // Remember for a short time that the player was on ice and therefore + // should be allowed to move a bit faster public int onIce; + // Where should a player be teleported back to when failing the check public final PreciseLocation runflySetBackPoint = new PreciseLocation(); + // Some values for estimating movement freedom public double vertFreedom; public double vertVelocity; public int vertVelocityCounter; public double horizFreedom; public int horizVelocityCounter; - - public float fallDistance; - public float lastAddedFallDistance; - public double horizontalBuffer; public int bunnyhopdelay; + // Keep track of estimated fall distance to compare to real fall distance + public float fallDistance; + public float lastAddedFallDistance; + + // Keep track of when "morePackets" last time checked and how much packets + // a player sent and may send before failing the check public long morePacketsLastTime; + public int packets; public int morePacketsBuffer = 50; + // Where to teleport the player that fails the "morepackets" check public final PreciseLocation morePacketsSetbackPoint = new PreciseLocation(); + // When NoCheat does teleport the player, remember the target location to + // be able to distinguish "our" teleports from teleports of others public final PreciseLocation teleportTo = new PreciseLocation(); + // For logging and convenience, make copies of the events locations public final PreciseLocation from = new PreciseLocation(); public final PreciseLocation to = new PreciseLocation(); + // For convenience, remember if the locations are considered "on ground" + // by NoCheat public boolean fromOnOrInGround; public boolean toOnOrInGround; public Id statisticCategory = Id.MOV_RUNNING; - public int packets; - public void clearRunFlyData() { runflySetBackPoint.reset(); jumpPhase = 0; diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/moving/NoFallCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/moving/NoFallCheck.java index 5e3e51f3..d80f6ed6 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/moving/NoFallCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/moving/NoFallCheck.java @@ -41,6 +41,9 @@ public class NoFallCheck extends MovingCheck { data.fallDistance = player.getPlayer().getFallDistance(); data.nofallVL += data.fallDistance; incrementStatistics(player, Id.MOV_NOFALL, data.fallDistance); + + // Execute whatever actions are associated with this check and the + // violation level and find out if we should cancel the event final boolean cancel = executeActions(player, cc.nofallActions, data.nofallVL); if(cancel) { player.dealFallDamage(); @@ -64,6 +67,8 @@ public class NoFallCheck extends MovingCheck { data.nofallVL += difference; incrementStatistics(player, Id.MOV_NOFALL, difference); + // Execute whatever actions are associated with this check and the + // violation level and find out if we should cancel the event final boolean cancel = executeActions(player, cc.nofallActions, data.nofallVL); // If "cancelled", the fall damage gets dealt in a way that's @@ -106,7 +111,7 @@ public class NoFallCheck extends MovingCheck { } // Reduce falldamage violation level - data.nofallVL *= 0.99D; + data.nofallVL *= 0.95D; return; } @@ -115,9 +120,9 @@ public class NoFallCheck extends MovingCheck { public String getParameter(ParameterName wildcard, NoCheatPlayer player) { if(wildcard == ParameterName.VIOLATIONS) - return String.format(Locale.US, "%d", (int) getData(player.getDataStore()).nofallVL); + return String.format(Locale.US, "%d", (int) getData(player).nofallVL); else if(wildcard == ParameterName.FALLDISTANCE) - return String.format(Locale.US, "%.2f", getData(player.getDataStore()).fallDistance); + return String.format(Locale.US, "%.2f", getData(player).fallDistance); else return super.getParameter(wildcard, player); } diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/moving/RunningCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/moving/RunningCheck.java index affffae1..4b6e4565 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/moving/RunningCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/moving/RunningCheck.java @@ -72,8 +72,8 @@ public class RunningCheck extends MovingCheck { // Slowly reduce the level with each event data.runflyVL *= 0.95; + // Did the player move in unexpected ways? if(result > 0) { - // Increment violation counter data.runflyVL += result; @@ -92,15 +92,24 @@ public class RunningCheck extends MovingCheck { } } else { + // Decide if we should create a new setBack point + // These are the result of a lot of bug reports, experience and + // trial and error + if((toInGround && from.y >= to.y) || CheckUtil.isLiquid(toType)) { + // Yes, if the player moved down "into" the ground or into liquid setBack.set(to); setBack.y = Math.ceil(setBack.y); data.jumpPhase = 0; } else if(toOnGround && (from.y >= to.y || setBack.y <= Math.floor(to.y))) { + // Yes, if the player moved down "onto" the ground and the new + // setback point is higher up than the old or at least at the + // same height setBack.set(to); setBack.y = Math.floor(setBack.y); data.jumpPhase = 0; } else if(fromOnGround || fromInGround || toOnGround || toInGround) { + // The player at least touched the ground somehow data.jumpPhase = 0; } } @@ -134,7 +143,7 @@ public class RunningCheck extends MovingCheck { Id statisticsCategory = null; - // Player on ice? + // Player on ice? Give him higher max speed Block b = player.getPlayer().getLocation().getBlock(); if(b.getType() == Material.ICE || b.getRelative(0, -1, 0).getType() == Material.ICE) { data.onIce = 20; @@ -208,6 +217,7 @@ public class RunningCheck extends MovingCheck { // How much higher did the player move than expected?? double distanceAboveLimit = 0.0D; + // Potion effect "Jump" double jumpAmplifier = player.getJumpAmplifier(); if(jumpAmplifier > data.lastJumpAmplifier) { data.lastJumpAmplifier = jumpAmplifier; @@ -239,9 +249,9 @@ public class RunningCheck extends MovingCheck { if(wildcard == ParameterName.CHECK) // Workaround for something until I find a better way to do it - return getData(player.getDataStore()).statisticCategory.toString(); + return getData(player).statisticCategory.toString(); else if(wildcard == ParameterName.VIOLATIONS) - return String.format(Locale.US, "%d", (int) getData(player.getDataStore()).runflyVL); + return String.format(Locale.US, "%d", (int) getData(player).runflyVL); else return super.getParameter(wildcard, player); } diff --git a/src/cc/co/evenprime/bukkit/nocheat/command/CommandHandler.java b/src/cc/co/evenprime/bukkit/nocheat/command/CommandHandler.java index e0cdadcd..ec5993fc 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/command/CommandHandler.java +++ b/src/cc/co/evenprime/bukkit/nocheat/command/CommandHandler.java @@ -13,14 +13,19 @@ import org.bukkit.permissions.Permission; import cc.co.evenprime.bukkit.nocheat.NoCheat; import cc.co.evenprime.bukkit.nocheat.config.Permissions; +/** + * Handle all NoCheat related commands in a common place + */ public class CommandHandler { private final List perms; - + public CommandHandler(NoCheat plugin) { // Make a copy to allow sorting perms = new LinkedList(plugin.getDescription().getPermissions()); + // Sort NoCheats permission by name and parent-child relation with + // a custom sorting method Collections.sort(perms, new Comparator() { public int compare(Permission o1, Permission o2) { @@ -44,10 +49,19 @@ public class CommandHandler { }); } + /** + * Handle a command that is directed at NoCheat + * @param plugin + * @param sender + * @param command + * @param label + * @param args + * @return + */ public boolean handleCommand(NoCheat plugin, CommandSender sender, Command command, String label, String[] args) { boolean result = false; - // Not our command + // Not our command, how did it get here? if(!command.getName().equalsIgnoreCase("nocheat") || args.length == 0) { result = false; } else if(args[0].equalsIgnoreCase("permlist") && args.length >= 2) { @@ -60,7 +74,7 @@ public class CommandHandler { } else if(args[0].equalsIgnoreCase("playerinfo") && args.length >= 2) { - // performance command was used + // playerinfo command was used result = handlePlayerInfoCommand(plugin, sender, args); } @@ -117,9 +131,8 @@ public class CommandHandler { sender.sendMessage("[NoCheat] Reloading configuration"); plugin.reloadConfiguration(); sender.sendMessage("[NoCheat] Configuration reloaded"); - } - else { - sender.sendMessage("You lack the "+Permissions.ADMIN_RELOAD+ " permission to use 'reload'"); + } else { + sender.sendMessage("You lack the " + Permissions.ADMIN_RELOAD + " permission to use 'reload'"); } return true; diff --git a/src/cc/co/evenprime/bukkit/nocheat/config/ActionFactory.java b/src/cc/co/evenprime/bukkit/nocheat/config/ActionFactory.java index e9cb49c9..a53c8196 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/config/ActionFactory.java +++ b/src/cc/co/evenprime/bukkit/nocheat/config/ActionFactory.java @@ -11,6 +11,10 @@ import cc.co.evenprime.bukkit.nocheat.actions.types.DummyAction; import cc.co.evenprime.bukkit.nocheat.actions.types.LogAction; import cc.co.evenprime.bukkit.nocheat.actions.types.SpecialAction; +/** + * Helps with creating Actions out of text string definitions + * + */ public class ActionFactory { private static final Map lib = new HashMap(); diff --git a/src/cc/co/evenprime/bukkit/nocheat/config/ConfPaths.java b/src/cc/co/evenprime/bukkit/nocheat/config/ConfPaths.java index 58b080f7..b28a31b1 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/config/ConfPaths.java +++ b/src/cc/co/evenprime/bukkit/nocheat/config/ConfPaths.java @@ -2,6 +2,8 @@ package cc.co.evenprime.bukkit.nocheat.config; /** * Paths for the configuration options + * Making everything final static prevents accidentially modifying any + * of these * */ public abstract class ConfPaths { diff --git a/src/cc/co/evenprime/bukkit/nocheat/debug/ActiveCheckPrinter.java b/src/cc/co/evenprime/bukkit/nocheat/debug/ActiveCheckPrinter.java index d7a02b78..4c17e542 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/debug/ActiveCheckPrinter.java +++ b/src/cc/co/evenprime/bukkit/nocheat/debug/ActiveCheckPrinter.java @@ -6,6 +6,10 @@ import cc.co.evenprime.bukkit.nocheat.EventManager; import cc.co.evenprime.bukkit.nocheat.NoCheat; import cc.co.evenprime.bukkit.nocheat.config.ConfigurationCacheStore; +/** + * Prints the list of active checks per world on startup, if requested + * + */ public class ActiveCheckPrinter { public static void printActiveChecks(NoCheat plugin, List eventManagers) { diff --git a/src/cc/co/evenprime/bukkit/nocheat/debug/LagMeasureTask.java b/src/cc/co/evenprime/bukkit/nocheat/debug/LagMeasureTask.java index d1e92160..942a5bb2 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/debug/LagMeasureTask.java +++ b/src/cc/co/evenprime/bukkit/nocheat/debug/LagMeasureTask.java @@ -3,6 +3,12 @@ package cc.co.evenprime.bukkit.nocheat.debug; import org.bukkit.World; import cc.co.evenprime.bukkit.nocheat.NoCheat; +/** + * A task running in the background that measures tick time vs. real time + * + * @author Evenprime + * + */ public class LagMeasureTask implements Runnable { private int ingameseconds = 1;