Fixed some problematic cases with teleports

Replaced flight-check completely with newer version
Fixed descriptions.txt file not getting automatically generated as
promised
This commit is contained in:
Evenprime 2011-07-11 15:34:32 +02:00
parent 0dea0c0285
commit ad78a91aab
21 changed files with 504 additions and 297 deletions

View File

@ -3,7 +3,7 @@ name: NoCheat
author: Evenprime
main: cc.co.evenprime.bukkit.nocheat.NoCheat
version: 1.08c
version: 1.09
softdepend: [ Permissions, CraftIRC ]

View File

@ -17,7 +17,7 @@ public class LogAction extends Action {
public final static LogAction[] log = { loglow, logmed, loghigh };
public LogAction(int firstAfter, boolean repeat, Level level) {
private LogAction(int firstAfter, boolean repeat, Level level) {
super(firstAfter, repeat);
this.level = level;
}

View File

@ -16,24 +16,25 @@ public abstract class Check {
private boolean active = false;
private boolean listenersRegistered = false;
private int permission;
private String name;
protected NoCheat plugin;
private final int permission;
private final String name;
protected final NoCheat plugin;
// Should OPs be checked if Permissions plugin is not available?
protected boolean checkOPs = false;
public boolean checkOPs;
protected Check(NoCheat plugin, String name, int permission, NoCheatConfiguration config) {
this.plugin = plugin;
this.permission = permission;
this.name = name;
try {
checkOPs = config.getBooleanValue(name + ".checkops");
checkOPs= config.getBooleanValue(name + ".checkops");
} catch (ConfigurationException e) {
checkOPs = false;
}
configure(config);
}

View File

@ -0,0 +1,114 @@
package cc.co.evenprime.bukkit.nocheat.checks;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import cc.co.evenprime.bukkit.nocheat.data.MovingData;
/**
* Check if the player should be allowed to make that move, e.g. is he allowed to jump here or move that far in one step
*
* @author Evenprime
*
*/
public class FlyingCheck {
public FlyingCheck() { }
// How many move events can a player have in air before he is expected to lose altitude (or eventually land somewhere)
private final static int jumpingLimit = 5;
// How high may a player get compared to his last location with ground contact
private final static double jumpHeight = 1.31D;
// How much points should hovering attempts cause?
private final static double hoveringPunishment = 0.2D;
// How high may a player move in one event on ground
private final static double stepHeight = 0.501D;
/**
* Calculate if and how much the player "failed" this check. The check should not
* modify any data
*
*/
public double check(final Player player, final Location from, final boolean fromOnGround, final Location to, final boolean toOnGround, final MovingData data) {
// How much higher did the player move than expected??
double distanceAboveLimit = 0.0D;
final double toY = to.getY();
final double fromY = from.getY();
double limit = calculateVerticalLimit(data, fromOnGround) + jumpHeight;
// Walk or start Jump
if(fromOnGround)
{
distanceAboveLimit = toY - fromY - limit;
}
// Land or Fly/Fall
else
{
final Location l;
if(data.setBackPoint == null)
l = from;
else
l = data.setBackPoint;
if(data.jumpPhase > jumpingLimit) {
limit -= (data.jumpPhase-jumpingLimit) * 0.2D;
}
if(toOnGround) limit += stepHeight;
distanceAboveLimit = toY - l.getY() - limit;
// Always give some bonus points in case of identical Y values in midair (hovering player)
if(fromY == toY && !toOnGround) {
distanceAboveLimit = Math.max(hoveringPunishment, distanceAboveLimit+hoveringPunishment);
}
}
return distanceAboveLimit;
}
private double calculateVerticalLimit(final MovingData data, final boolean onGroundFrom) {
// 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" packet a short time ago
if(data.maxYVelocity > 0.0D) {
data.vertFreedomCounter = 30;
// Be generous with the height limit for the client
data.vertFreedom += data.maxYVelocity*2D;
data.maxYVelocity = 0.0D;
}
// consume a counter for this client
if(data.vertFreedomCounter > 0) {
data.vertFreedomCounter--;
}
final double limit = data.vertFreedom;
// If the event counter has been consumed, remove the vertical movement limit increase when landing the next time
if(onGroundFrom && data.vertFreedomCounter <= 0) {
data.vertFreedom = 0.0D;
}
return limit;
}
}

View File

@ -12,8 +12,6 @@ import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.Listener;
import org.bukkit.event.Event.Priority;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.plugin.PluginManager;
import org.bukkit.util.Vector;
@ -41,29 +39,19 @@ public class MovingCheck extends Check {
public MovingCheck(NoCheat plugin, NoCheatConfiguration config) {
super(plugin, "moving", PermissionData.PERMISSION_MOVING, config);
helper = new MovingEventHelper();
flyingCheck = new FlyingCheck();
runningCheck = new RunningCheck();
}
// How many move events can a player have in air before he is expected to lose altitude (or land somewhere)
private final static int jumpingLimit = 5;
// How high may a player get compared to his last location with ground contact
private final static double jumpHeight = 1.35D;
// How high may a player move in one event on ground
private final static double stepHeight = 0.501D;
private final static double stepWidth = 0.22D;
private final static double sneakWidth = 0.14D;
private final static double swimWidth = 0.18D;
private int ticksBeforeSummary = 100;
private final int ticksBeforeSummary = 100;
public long statisticElapsedTimeNano = 0;
public boolean allowFlying;
public boolean allowFakeSneak;
public boolean allowFastSwim;
public boolean checkOPs;
private boolean waterElevators;
@ -77,6 +65,9 @@ public class MovingCheck extends Check {
private boolean enforceTeleport;
private final MovingEventHelper helper;
private final FlyingCheck flyingCheck;
private final RunningCheck runningCheck;
private static final double magic = 0.30000001192092896D;
@ -90,203 +81,88 @@ public class MovingCheck extends Check {
* Fourth treat any occured violations as configured
* @param event
*/
public void check(final PlayerMoveEvent event) {
final Player player = event.getPlayer();
// Should we check at all
if(skipCheck(player)) { return; }
final long startTime = System.nanoTime();
// Get the player-specific data
final MovingData data = MovingData.get(player);
// Get the two locations of the event
final Location to = event.getTo();
Location from = event.getFrom();
public Location check(Player player, Location from, Location to,
MovingData data) {
updateVelocity(player.getVelocity(), data);
Location newToLocation = null;
final long startTime = System.nanoTime();
/************* DECIDE WHICH CHECKS NEED TO BE RUN *************/
final boolean flyCheck = !allowFlying && !plugin.hasPermission(player, PermissionData.PERMISSION_FLYING, checkOPs);
final boolean runCheck = true;
// event.getFrom() is intentional here
if(shouldBeIgnored(player, data, from, to)) {
statisticElapsedTimeNano += System.nanoTime() - startTime;
statisticTotalEvents++;
return;
}
/***************** REFINE EVENT DATA FOR CHECKS ***************/
/**** Horizontal movement check START ****/
if(flyCheck || runCheck) {
// In both cases it will be interesting to know the type of underground the player
// is in or goes to
final int fromType = helper.isLocationOnGround(from.getWorld(), from.getX(), from.getY(), from.getZ(), false);
final int toType = helper.isLocationOnGround(to.getWorld(), to.getX(), to.getY(),to.getZ(), false);
// First check the distance the player has moved horizontally
final double xDistance = from.getX()-to.getX();
final double zDistance = from.getZ()-to.getZ();
final boolean fromOnGround = fromType != MovingEventHelper.NONSOLID;
final boolean toOnGround = toType != MovingEventHelper.NONSOLID;
double combined = Math.sqrt((xDistance*xDistance + zDistance*zDistance));
// Distribute data to checks in the form needed by the checks
// If the target is a bed and distance not too big, allow it always
// Bukkit prevents using blocks behind walls already, so I don't have to check for that
if(to.getWorld().getBlockTypeIdAt(to) == Material.BED_BLOCK.getId() && combined < 8.0D) {
statisticElapsedTimeNano += System.nanoTime() - startTime;
statisticTotalEvents++;
return;
}
/********************* EXECUTE THE CHECKS ********************/
double result = 0.0D;
final int onGroundFrom = playerIsOnGround(from, 0.0D);
double overLimit = 0.0D;
if(player.isSneaking() && !allowFakeSneak && !plugin.hasPermission(player, PermissionData.PERMISSION_FAKESNEAK, checkOPs)) {
overLimit = Math.max(0.0D, combined - (data.horizFreedom + sneakWidth));
}
else if(onGroundFrom == MovingData.LIQUID && !allowFastSwim && !plugin.hasPermission(player, PermissionData.PERMISSION_FASTSWIM, checkOPs)) {
overLimit = Math.max(0.0D, combined - (data.horizFreedom + swimWidth));
}
else {
overLimit = Math.max(0.0D, combined - (data.horizFreedom + stepWidth));
}
data.runningThreshold += overLimit;
int violationLevelHorizontal = limitCheck(data.runningThreshold - 1);
// Reduce horiz moving freedom with each event
data.runningThreshold *= 0.97;
data.horizFreedom *= 0.9;
/**** Horizontal movement check END ****/
/**** Vertical movement check START ****/
int violationLevelVertical = -1;
// The location we'd use as a new setback if there are no violations
Location newSetBack = null;
double limit = calculateVerticalLimit(data, onGroundFrom);
// Handle 4 distinct cases: Walk, Jump, Land, Fly
// Walk or start Jump
if(onGroundFrom != MovingData.NONSOLID)
{
limit += jumpHeight;
final double distance = to.getY() - from.getY();
violationLevelVertical = limitCheck(distance - limit);
if(violationLevelVertical < 0)
{
// reset jumping
data.jumpPhase = 0;
newSetBack = from;
if(flyCheck) {
result += Math.max(0D, flyingCheck.check(player, from, fromOnGround, to, toOnGround, data));
}
}
// Land or Fly/Fall
else
{
final Location l;
final boolean canFly = allowFlying || plugin.hasPermission(player, PermissionData.PERMISSION_FLYING, checkOPs);
if(runCheck) {
result += Math.max(0D, runningCheck.check(from, to,
player.isSneaking(), (fromType & toType & MovingEventHelper.LIQUID) > 0, data));
}
if(data.setBackPoint == null || canFly)
l = from;
else
l = data.setBackPoint;
if(!canFly && data.jumpPhase > jumpingLimit)
limit += jumpHeight - (data.jumpPhase-jumpingLimit) * 0.2D;
else limit += jumpHeight;
/********* HANDLE/COMBINE THE RESULTS OF THE CHECKS ***********/
final int onGroundTo = playerIsOnGround(to, 0.0D);
if(onGroundTo != MovingData.NONSOLID) limit += stepHeight;
final double distance = to.getY() - l.getY();
// Check if player isn't jumping too high
violationLevelVertical = limitCheck(distance - limit);
if(violationLevelVertical < 0) {
if(onGroundTo != MovingData.NONSOLID) { // Land
data.jumpPhase = 0; // He is on ground now, so reset the jump
//newSetBack = to;
data.jumpPhase++;
if(result <= 0) {
if(fromOnGround) {
data.setBackPoint = from;
data.jumpPhase = 0;
}
else { // Fly
data.jumpPhase++; // Enter next phase of the flight
// If we have no setback point, create one now
if(data.setBackPoint == null) {
newSetBack = from;
}
else if(toOnGround) {
data.jumpPhase = 0;
}
}
else if(result > 0) {
// Increment violation counter
data.violationLevel += result;
if(data.setBackPoint == null) data.setBackPoint = from;
}
if(result > 0 && data.violationLevel > 1) {
setupSummaryTask(player, data);
int level = limitCheck(data.violationLevel-1);
data.violationsInARow[level]++;
newToLocation = action(player, from, to, actions[level], data.violationsInARow[level], data);
}
}
/**** Vertical movement check END ****/
/****** Violation Handling START *****/
int violationLevel = violationLevelHorizontal > violationLevelVertical ? violationLevelHorizontal : violationLevelVertical;
if(violationLevel < 0 && newSetBack != null) {
data.setBackPoint = newSetBack;
}
// If we haven't already got a setback point by now, make this location the new setback point
if(data.setBackPoint == null) {
data.setBackPoint = from;
}
if(violationLevel >= 0) {
setupSummaryTask(event.getPlayer(), data);
data.violationsInARow[violationLevel]++;
action(event, event.getPlayer(), from, to, actions[violationLevel], data.violationsInARow[violationLevel], data);
}
/****** Violation Handling END *****/
// Slowly reduce the level with each event
data.violationLevel *= 0.97;
data.horizFreedom *= 0.97;
statisticElapsedTimeNano += System.nanoTime() - startTime;
statisticTotalEvents++;
}
private double calculateVerticalLimit(final MovingData data, final int onGroundFrom) {
// 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" packet a short time ago
if(data.maxYVelocity > 0.0D) {
data.vertFreedomCounter = 30;
// Be generous with the height limit for the client
data.vertFreedom += data.maxYVelocity*2D;
data.maxYVelocity = 0.0D;
}
// consume a counter for this client
if(data.vertFreedomCounter > 0) {
data.vertFreedomCounter--;
}
final double limit = data.vertFreedom;
// If the event counter has been consumed, remove the vertical movement limit increase when landing the next time
if(onGroundFrom != MovingData.NONSOLID && data.vertFreedomCounter <= 0) {
data.vertFreedom = 0.0D;
}
return limit;
return newToLocation;
}
/**
@ -297,45 +173,35 @@ public class MovingCheck extends Check {
* @param to
* @return
*/
private boolean shouldBeIgnored(final Player player, final MovingData data, final Location from, final Location to) {
public boolean shouldBeApplied(final Player player, final MovingData data, final Location from, final Location to) {
if(data.firstEventAfterRespawn) {
data.firstEventAfterRespawn = false;
data.teleportTo = from.clone();
if(player.isDead() || player.isInsideVehicle() || data.insideVehicle) return false;
if(data.wasTeleported) {
// Remember this location
data.teleportedTo = from.clone();
data.wasTeleported = false;
data.jumpPhase = 0;
}
// Now it gets complicated: (a friendly reminder to myself why this actually works in CB 950+)
// data.teleportTo gets a location assigned if a teleport event is successfully executed.
// But there is a delay between the serverside execution of the teleport (instantly) and
// the execution on the client side (may take an arbitrary time). During that time, the
// client may send new move events relative to his old location. These events get treated
// by bukkit as PLAYER_MOVE events, despite the server not accepting them (the players
// serverside location won't get updated). Therefore comparing the teleport destination
// with the servers location of the player (which is almost the same as the "from" location
// in the move event) tells us if the server is still waiting for the clientside teleporting
// to be executed. We are only interested in client's move events after it executed the
// teleport, therefore just ignore all events before that.
if(data.teleportTo != null && data.teleportTo.getWorld().equals(from.getWorld())) {
if(data.teleportTo.distanceSquared(from) < 0.01D) {
return true;
if(data.teleportedTo != null && data.teleportedTo.getWorld().equals(from.getWorld())) {
// As long as the from-Location doesn't change, the player didn't accept the teleport
if(data.teleportedTo.distanceSquared(from) < 0.01D) {
// Event after Teleport ignored
return false;
}
else {
data.teleportTo = null;
// The player finally accepted the teleport with the previous event
data.teleportedTo = null;
}
}
// Dead or in vehicles -> I don't care
if(player.isDead() || data.insideVehicle || player.isInsideVehicle()) {
return true;
}
// If the player moved between worlds between events, don't check (wouldn't make sense
// to check coordinates between different worlds...)
if(!from.getWorld().equals(data.lastSeenInWorld)) {
return true;
// If the target is a bed, don't check (going to bed is a kind of mini teleport...)
if(to.getWorld().getBlockTypeIdAt(to) == Material.BED_BLOCK.getId()) {
return false;
}
return false;
return true;
}
@ -355,6 +221,8 @@ public class MovingCheck extends Check {
if(data.highestLogLevel != null) {
String logString = String.format(summaryMessage, p.getName(), ticksBeforeSummary/20, data.violationsInARow[0], data.violationsInARow[1],data.violationsInARow[2]);
plugin.log(data.highestLogLevel, logString);
data.highestLogLevel = Level.ALL;
}
// deleting its own reference
data.summaryTask = -1;
@ -388,7 +256,7 @@ public class MovingCheck extends Check {
}
if(!event.isCancelled()) {
data.teleportTo = event.getTo().clone();
data.wasTeleported = true;
data.setBackPoint = event.getTo().clone();
//data.lastLocation = event.getTo().clone();
}
@ -397,17 +265,6 @@ public class MovingCheck extends Check {
data.jumpPhase = 0;
}
/**
* Set a flag to declare that the player recently respawned
* @param event
*/
public void respawned(PlayerRespawnEvent event) {
MovingData data = MovingData.get(event.getPlayer());
data.firstEventAfterRespawn = true;
data.jumpPhase = 0;
data.setBackPoint = null;
}
/**
* Update the cached values for players velocity to be prepared to
* give them additional movement freedom in their next move events
@ -430,13 +287,16 @@ public class MovingCheck extends Check {
* Perform actions that were specified in the config file
* @param event
* @param action
* @return
*/
private void action(PlayerMoveEvent event, Player player, Location from, Location to, Action[] actions, int violations, MovingData data) {
private Location action( Player player, Location from, Location to, Action[] actions, int violations, MovingData data) {
if(actions == null) return;
Location newToLocation = null;
if(actions == null) return newToLocation;
boolean cancelled = false;
for(Action a : actions) {
if(a.firstAfter <= violations) {
if(a.firstAfter == violations || a.repeat) {
@ -469,9 +329,9 @@ public class MovingCheck extends Check {
data.setBackPoint.setY(y);
// Remember the location we send the player to, to identify teleports that were started by us
data.teleportInitializedByMe = new Location(data.setBackPoint.getWorld(), data.setBackPoint.getX(), y, data.setBackPoint.getZ(), event.getTo().getYaw(), event.getTo().getPitch());
data.teleportInitializedByMe = new Location(data.setBackPoint.getWorld(), data.setBackPoint.getX(), y, data.setBackPoint.getZ(), to.getYaw(), to.getPitch());
event.setTo(data.teleportInitializedByMe);
newToLocation = data.teleportInitializedByMe;
cancelled = true; // just prevent us from treating more than one "cancel" action, which would make no sense
}
@ -480,6 +340,8 @@ public class MovingCheck extends Check {
}
}
}
return newToLocation;
}
/**
@ -633,6 +495,8 @@ public class MovingCheck extends Check {
waterElevators = config.getBooleanValue("moving.waterelevators");
checkOPs = config.getBooleanValue("moving.checkops");
logMessage = config.getStringValue("moving.logmessage").
replace("[player]", "%1$s").
replace("[world]", "%2$s").
@ -674,6 +538,8 @@ public class MovingCheck extends Check {
pm.registerEvent(Event.Type.PLAYER_MOVE, movingPlayerMonitor, Priority.Monitor, plugin);
pm.registerEvent(Event.Type.ENTITY_DAMAGE, new MovingEntityListener(this), Priority.Monitor, plugin);
pm.registerEvent(Event.Type.PLAYER_TELEPORT, new MovingPlayerMonitor(this), Priority.Monitor, plugin);
pm.registerEvent(Event.Type.PLAYER_RESPAWN, new MovingPlayerMonitor(this), Priority.Monitor, plugin);
pm.registerEvent(Event.Type.PLAYER_PORTAL, new MovingPlayerMonitor(this), Priority.Monitor, plugin);
}
}

View File

@ -0,0 +1,170 @@
package cc.co.evenprime.bukkit.nocheat.checks;
import net.minecraft.server.Block;
import org.bukkit.Material;
import org.bukkit.World;
/**
* A collection of stuff to process data of move events
* @author Evenprime
*
*/
public class MovingEventHelper {
private final double magic = 0.30000001192092896D;
private final double magic2 = 0.69999998807907103D;
// Block types that may need to be treated specially
public static final int NONSOLID = 0; // 0x00000000
public static final int SOLID = 1; // 0x00000001
public static final int LIQUID = 2; // 0x00000010
public static final int LADDER = 4; // 0x00000100
public static final int FENCE = 8; // 0x00001000
// Until I can think of a better way to determine if a block is solid or not, this is what I'll do
private final int types[] = new int[256];
public MovingEventHelper() {
// Find and define properties of all blocks
for(int i = 0; i < types.length; i++) {
// Everything is considered nonsolid at first
types[i] = NONSOLID;
if(Block.byId[i] != null) {
if(Block.byId[i].material.isSolid()) {
// solid blocks like STONE, CAKE, TRAPDOORS
types[i] = SOLID;
}
else if(Block.byId[i].material.isLiquid()){
// WATER, LAVA
types[i] = LIQUID;
}
}
}
// Special types just for me
types[Material.LADDER.getId()]= LADDER | SOLID;
types[Material.FENCE.getId()]= FENCE | SOLID;
}
/**
* Check if certain coordinates are considered "on ground"
*
* @param w The world the coordinates belong to
* @param values The coordinates [lowerX, higherX, Y, lowerZ, higherZ] to be checked
* @param l The precise location that was used for calculation of "values"
* @return
*/
public int isLocationOnGround(final World world, final double x, final double y, final double z, boolean waterElevatorsAllowed) {
final int lowerX = lowerBorder(x);
final int upperX = upperBorder(x);
final int Y = (int)Math.floor(y);
final int lowerZ = lowerBorder(z);
final int higherZ = upperBorder(z);
int result;
// check in what kind of block the player is standing "in"
result = types[world.getBlockTypeIdAt(lowerX, Y, lowerZ)] | types[world.getBlockTypeIdAt(upperX, Y, lowerZ)] |
types[world.getBlockTypeIdAt(lowerX, Y, higherZ)] | types[world.getBlockTypeIdAt(upperX, Y, higherZ)];
if((result & SOLID) != 0) {
// return standing
return SOLID;
}
else if((result & LIQUID) != 0) {
// return swimming
return LIQUID;
}
// Check the four borders of the players hitbox for something he could be standing on
result = types[world.getBlockTypeIdAt(lowerX, Y-1, lowerZ)] | types[world.getBlockTypeIdAt(upperX, Y-1, lowerZ)] |
types[world.getBlockTypeIdAt(lowerX, Y-1, higherZ)] | types[world.getBlockTypeIdAt(upperX, Y-1, higherZ)];
if((result & SOLID) != 0) {
// return standing
return SOLID;
}
// check if his head is "stuck" in an block
result = types[world.getBlockTypeIdAt(lowerX, Y+1, lowerZ)] | types[world.getBlockTypeIdAt(upperX, Y+1, lowerZ)] |
types[world.getBlockTypeIdAt(lowerX, Y+1, higherZ)] | types[world.getBlockTypeIdAt(upperX, Y+1, higherZ)];
if((result & SOLID) != 0) {
// return standing
return SOLID;
}
else if((result & LIQUID) != 0) {
// return swimming
return LIQUID;
}
// Running on fences causes problems if not treated specially
result = types[world.getBlockTypeIdAt(lowerX, Y-2, lowerZ)] | types[world.getBlockTypeIdAt(upperX, Y-2, lowerZ)] |
types[world.getBlockTypeIdAt(lowerX, Y-2, higherZ)] | types[world.getBlockTypeIdAt(upperX, Y-2, higherZ)];
if((result & FENCE) != 0) {
// return standing
return SOLID;
}
// Water elevators - optional "feature"
if(waterElevatorsAllowed) {
result = types[world.getBlockTypeIdAt(lowerX+1, Y+1, lowerZ+1)] |
types[world.getBlockTypeIdAt(lowerX+1, Y , lowerZ+1)] |
types[world.getBlockTypeIdAt(lowerX, Y+1, lowerZ+1)] |
types[world.getBlockTypeIdAt(lowerX , Y , lowerZ+1)] |
types[world.getBlockTypeIdAt(lowerX+1, Y+1, lowerZ )] |
types[world.getBlockTypeIdAt(lowerX+1, Y , lowerZ )] ;
if((result & LIQUID) != 0) {
return SOLID; // Solid? Why that? Because that's closer to what the bug actually does than liquid
}
}
// If nothing matches, he is somewhere in the air
return NONSOLID;
}
/**
* Personal Rounding function to determine if a player is still touching a block or not
* @param d1
* @return
*/
private int lowerBorder(double d1) {
double floor = Math.floor(d1);
double d4 = floor + magic;
if(d4 <= d1)
d4 = 0;
else
d4 = 1;
return (int) (floor - d4);
}
/**
* Personal Rounding function to determine if a player is still touching a block or not
* @param d1
* @return
*/
private int upperBorder(double d1) {
double floor = Math.floor(d1);
double d4 = floor + magic2;
if(d4 < d1)
d4 = -1;
else
d4 = 0;
return (int) (floor - d4);
}
}

View File

@ -0,0 +1,39 @@
package cc.co.evenprime.bukkit.nocheat.checks;
import org.bukkit.Location;
import cc.co.evenprime.bukkit.nocheat.data.MovingData;
public class RunningCheck {
private final static double stepWidth = 0.22D;
private final static double sneakWidth = 0.14D;
private final static double swimWidth = 0.18D;
public RunningCheck() { }
public double check(final Location from, final Location to, final boolean isSneaking, final boolean isSwimming, final MovingData data) {
// How much further did the player move than expected??
double distanceAboveLimit = 0.0D;
// First calculate the distance the player has moved horizontally
final double xDistance = from.getX()-to.getX();
final double zDistance = from.getZ()-to.getZ();
final double totalDistance = Math.sqrt((xDistance*xDistance + zDistance*zDistance));
// TODO: Also ask cc which to apply
if(isSneaking) {
distanceAboveLimit = totalDistance - sneakWidth;
}
else if(isSwimming) {
distanceAboveLimit = totalDistance - swimWidth;
}
else {
distanceAboveLimit = totalDistance - stepWidth;
}
return distanceAboveLimit;
}
}

View File

@ -21,8 +21,8 @@ public class LevelOption extends ChildOption {
HIGH("high", "very important messages", Level.SEVERE);
private final String value;
private String description;
private Level level;
private final String description;
private final Level level;
private LogLevel(String value, String description, Level level) {
this.value = value;

View File

@ -35,7 +35,7 @@ public class NoCheatConfiguration {
private ParentOption root;
private Map<String, Action> actionMap = new HashMap<String,Action>();
private final Map<String, Action> actionMap = new HashMap<String,Action>();
private Map<String, Object> yamlContent = new HashMap<String, Object>();
@ -50,6 +50,7 @@ public class NoCheatConfiguration {
// Setup the configuration tree
config(configurationFile, descriptionsFile);
}
/**
@ -266,7 +267,7 @@ public class NoCheatConfiguration {
}
writeConfigFile(configurationFile, this);
//writeDescriptionFile(descriptionsFile, this);
writeDescriptionFile(descriptionsFile, this);
}
public void setupFileLogger() {
@ -301,7 +302,7 @@ public class NoCheatConfiguration {
}
}
public Action[] stringToActions(String string) {
private Action[] stringToActions(String string) {
List<Action> as = new LinkedList<Action>();
String[] parts = string.split(" ");
@ -350,7 +351,7 @@ public class NoCheatConfiguration {
* Write a file with the descriptions of all options
* @param f
*/
public static void writeDescriptionFile(File f, NoCheatConfiguration configuration) {
private static void writeDescriptionFile(File f, NoCheatConfiguration configuration) {
try {
if(f.getParentFile() != null)
f.getParentFile().mkdirs();
@ -374,7 +375,7 @@ public class NoCheatConfiguration {
public int getIntegerValue(String optionName) throws ConfigurationException {
return getIntegerOption(optionName).getIntegerValue();
}
public IntegerOption getIntegerOption(String optionName) throws ConfigurationException {
private IntegerOption getIntegerOption(String optionName) throws ConfigurationException {
Option o = getOption(optionName) ;
if(o instanceof IntegerOption) {
@ -387,7 +388,7 @@ public class NoCheatConfiguration {
public String getStringValue(String optionName) throws ConfigurationException {
return getStringOption(optionName).getValue();
}
public TextFieldOption getStringOption(String optionName) throws ConfigurationException {
private TextFieldOption getStringOption(String optionName) throws ConfigurationException {
Option o = getOption(optionName);
if(o instanceof TextFieldOption) {
@ -400,7 +401,7 @@ public class NoCheatConfiguration {
public Level getLogLevelValue(String optionName) throws ConfigurationException {
return getLogLevelOption(optionName).getLevelValue();
}
public LevelOption getLogLevelOption(String optionName) throws ConfigurationException {
private LevelOption getLogLevelOption(String optionName) throws ConfigurationException {
Option o = getOption(optionName);
if(o instanceof LevelOption) {
@ -414,7 +415,8 @@ public class NoCheatConfiguration {
public boolean getBooleanValue(String optionName) throws ConfigurationException {
return getBooleanOption(optionName).getBooleanValue();
}
public BooleanOption getBooleanOption(String optionName) throws ConfigurationException {
private BooleanOption getBooleanOption(String optionName) throws ConfigurationException {
Option o = getOption(optionName);
if(o instanceof BooleanOption) {

View File

@ -12,8 +12,8 @@ public class ParentOption extends Option {
*/
private static final long serialVersionUID = 3162246550749560727L;
private LinkedList<Option> children = new LinkedList<Option>();
private boolean editable;
private final LinkedList<Option> children = new LinkedList<Option>();
private final boolean editable;
public ParentOption(String identifier, boolean editable) {
super(identifier);

View File

@ -8,7 +8,7 @@ public abstract class TextFieldOption extends ChildOption {
private static final long serialVersionUID = -8189248456599421250L;
private String value;
private int length = -1;
private final int length;
public TextFieldOption(String name, String initialValue, int preferredLength) {
@ -16,12 +16,6 @@ public abstract class TextFieldOption extends ChildOption {
this.value = initialValue;
this.length = preferredLength;
}
public TextFieldOption(String name, String parentName, String initialValue) {
super(name);
this.value = initialValue;
}
@Override
public String getValue() {

View File

@ -6,14 +6,13 @@ import net.minecraft.server.Block;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.Player;
import cc.co.evenprime.bukkit.nocheat.NoCheatData;
public class MovingData {
public int jumpPhase = 0;
public int violationsInARow[] = { 0, 0, 0 };
public final int violationsInARow[] = { 0, 0, 0 };
public double horizFreedom = 0.0D;
public double vertFreedom = 0.0D;
public int vertFreedomCounter = 0;
@ -25,18 +24,13 @@ public class MovingData {
public int summaryTask = -1;
public Level highestLogLevel = null;
public double maxYVelocity = 0.0D;
public double runningThreshold = 0.0D;
public double violationLevel = 0.0D;
public boolean insideVehicle = false;
// Use to determine if an move event should be handled
public Location teleportTo = null;
// Use to track the world the player is in
public World lastSeenInWorld = null;
public Location teleportInitializedByMe = null;
public boolean firstEventAfterRespawn = false;
public boolean wasTeleported = true;
public Location teleportedTo;
// Block types that may need to be treated specially
public static final int NONSOLID = 0; // 0x00000000
@ -80,7 +74,7 @@ public class MovingData {
if(data.moving == null) {
data.moving = new MovingData();
data.moving.lastSeenInWorld = p.getLocation().getWorld();
data.moving.teleportedTo = p.getLocation();
}
return data.moving;

View File

@ -6,8 +6,8 @@ import cc.co.evenprime.bukkit.nocheat.NoCheatData;
public class PermissionData {
public long lastUpdate[] = new long[11];
public boolean cache[] = new boolean[11];
public final long lastUpdate[] = new long[11];
public final boolean cache[] = new boolean[11];
public static final String[] permissionNames = new String[11];

View File

@ -13,7 +13,8 @@ import cc.co.evenprime.bukkit.nocheat.checks.AirbuildCheck;
*/
public class AirbuildBlockListener extends BlockListener {
private AirbuildCheck check;
private final AirbuildCheck check;
public AirbuildBlockListener(AirbuildCheck check) {
this.check = check;
}

View File

@ -9,7 +9,7 @@ import cc.co.evenprime.bukkit.nocheat.checks.BogusitemsCheck;
public class BogusitemsPlayerListener extends PlayerListener {
private BogusitemsCheck check;
private final BogusitemsCheck check;
public BogusitemsPlayerListener(BogusitemsCheck bogusitemsCheck) {
check = bogusitemsCheck;

View File

@ -9,7 +9,7 @@ import cc.co.evenprime.bukkit.nocheat.data.MovingData;
public class MovingEntityListener extends EntityListener {
private MovingCheck check;
private final MovingCheck check;
public MovingEntityListener(MovingCheck check) {
this.check = check;

View File

@ -1,10 +1,13 @@
package cc.co.evenprime.bukkit.nocheat.listeners;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerListener;
import org.bukkit.event.player.PlayerMoveEvent;
import cc.co.evenprime.bukkit.nocheat.checks.MovingCheck;
import cc.co.evenprime.bukkit.nocheat.data.MovingData;
/**
* Handle events for Player related events
@ -14,7 +17,7 @@ import cc.co.evenprime.bukkit.nocheat.checks.MovingCheck;
public class MovingPlayerListener extends PlayerListener {
private MovingCheck check;
private final MovingCheck check;
public MovingPlayerListener(MovingCheck check) {
this.check = check;
@ -23,6 +26,28 @@ public class MovingPlayerListener extends PlayerListener {
@Override
public void onPlayerMove(PlayerMoveEvent event) {
if(!event.isCancelled()) check.check(event);
if(event.isCancelled()) return;
final Player player = event.getPlayer();
// Is there something to do at all?
if(!check.skipCheck(player)) {
final MovingData data = MovingData.get(player);
final Location from = event.getFrom();
final Location to = event.getTo();
Location newTo = null;
if(check.shouldBeApplied(player, data, from, to)) {
// Check it
newTo = check.check(player, from, to, data);
}
// Did the checks decide we need a new To-Location?
if(newTo != null) {
event.setTo(new Location(newTo.getWorld(), newTo.getX(), newTo.getY(), newTo.getZ(), event.getTo().getYaw(), event.getTo().getPitch()));
}
}
}
}

View File

@ -3,7 +3,7 @@ package cc.co.evenprime.bukkit.nocheat.listeners;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerListener;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.player.PlayerPortalEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import cc.co.evenprime.bukkit.nocheat.checks.MovingCheck;
@ -16,21 +16,22 @@ import cc.co.evenprime.bukkit.nocheat.data.MovingData;
*/
public class MovingPlayerMonitor extends PlayerListener {
private MovingCheck check;
private final MovingCheck check;
public MovingPlayerMonitor(MovingCheck check) {
this.check = check;
}
@Override
public void onPlayerPortal(PlayerPortalEvent event) {
check.teleported(event);
}
@Override
public void onPlayerTeleport(PlayerTeleportEvent event) {
check.teleported(event);
}
@Override
public void onPlayerRespawn(PlayerRespawnEvent event) {
this.check.respawned(event);
}
@Override
public void onPlayerInteract(PlayerInteractEvent event) {
@ -41,7 +42,7 @@ public class MovingPlayerMonitor extends PlayerListener {
public void onPlayerMove(PlayerMoveEvent event) {
if(!event.isCancelled()) {
MovingData data = MovingData.get(event.getPlayer());
data.lastSeenInWorld = event.getPlayer().getLocation().getWorld();
if( event.getPlayer().isInsideVehicle()) {
data.setBackPoint = event.getTo();
}

View File

@ -7,7 +7,7 @@ import cc.co.evenprime.bukkit.nocheat.checks.NukeCheck;
public class NukeBlockListener extends BlockListener {
private NukeCheck check;
private final NukeCheck check;
public NukeBlockListener(NukeCheck check) {
this.check = check;

View File

@ -13,7 +13,7 @@ import cc.co.evenprime.bukkit.nocheat.checks.SpeedhackCheck;
*/
public class SpeedhackPlayerListener extends PlayerListener {
private SpeedhackCheck check;
private final SpeedhackCheck check;
public SpeedhackPlayerListener(SpeedhackCheck check) {
this.check = check;

View File

@ -87,7 +87,7 @@ public class SimpleYaml {
/* Convenience methods for retrieving values start here */
@SuppressWarnings("unchecked")
public static Object getProperty(String path, Map<String, Object> node) {
private final static Object getProperty(String path, Map<String, Object> node) {
if (!path.contains(".")) {
return node.get(path);
}