Finally a clean solution for getting stuck on ledges + resetting

player to his last valid location on the ground instead of somewhere
in midair + even less verbose logging (only show logs if the violating
player made 40 legitimate moves in a row. If he keeps doing
violations, just keep counting incidents).
This commit is contained in:
Evenprime 2011-03-08 19:12:45 +01:00
parent 4a09449d2c
commit 3bcb55d2b2
4 changed files with 93 additions and 67 deletions

View File

@ -3,7 +3,7 @@ name: NoCheatPlugin
author: Evenprime
main: cc.co.evenprime.bukkit.nocheat.NoCheatPlugin
version: 0.6.4
version: 0.6.4a
commands:
nocheat:

View File

@ -40,7 +40,7 @@ public class NoCheatConfiguration {
public static String speedhackActionNormal = "";
public static String speedhackActionHeavy = "";
public static int movingFreeMoves = 10;
public static int movingFreeMoves = 5;
// How should moving violations be treated?
public static String movingActionMinor = "";
@ -109,7 +109,7 @@ public class NoCheatConfiguration {
speedhackLimitMed = c.getInt("speedhack.limits.med", 45);
speedhackLimitHigh = c.getInt("speedhack.limits.high", 60);
movingFreeMoves = c.getInt("moving.freemoves", 10);
movingFreeMoves = c.getInt("moving.freemoves", 5);
movingActionMinor = c.getString("moving.action.low", "loglow reset");
movingActionNormal = c.getString("moving.action.med", "logmed reset");
@ -121,7 +121,7 @@ public class NoCheatConfiguration {
airbuildAction = c.getString("airbuild.action", "logmed deny");
if(movingFreeMoves < 10) movingFreeMoves = 10;
if(movingFreeMoves < 5) movingFreeMoves = 5;
}
/**

View File

@ -15,6 +15,7 @@ public class NoCheatData {
*/
public int movingJumpPhase = 0; // current jumpingPhase
public int movingLegitMovesInARow = 0;
public int movingMinorViolationsInARow = 0;
public int movingNormalViolationsInARow = 0;
public int movingHeavyViolationsInARow = 0;

View File

@ -29,6 +29,9 @@ public class MovingCheck {
public static double movingDistanceMed = 2.0D;
public static double movingDistanceHigh = 5.0D;
final static double magic = 0.30000001192092896D;
final static double magic2 = 0.69999998807907103D;
// Block types that may be treated specially
private enum BlockType {
SOLID, NONSOLID, LADDER, LIQUID, UNKNOWN;
@ -164,83 +167,87 @@ public class MovingCheck {
// pre-calculate boundary values that are needed multiple times in the following checks
// the array each contains [lowerX, higherX, Y, lowerZ, higherZ]
int fromValues[] = {floor_double(from.getX() - 0.3D), (int)Math.floor(from.getX() + 0.3D), from.getBlockY(), floor_double(from.getZ() - 0.3D),(int)Math.floor(from.getZ() + 0.3D) };
int toValues[] = {floor_double(to.getX() - 0.3D), (int)Math.floor(to.getX() + 0.3D), to.getBlockY(), floor_double(to.getZ() - 0.3D), (int)Math.floor(to.getZ() + 0.3D) };
int fromValues[] = {lowerBorder(from.getX()), upperBorder(from.getX()), from.getBlockY(), lowerBorder(from.getZ()),upperBorder(from.getZ()) };
int toValues[] = {lowerBorder(to.getX()), upperBorder(to.getX()), to.getBlockY(), lowerBorder(to.getZ()), upperBorder(to.getZ()) };
// compare locations to the world to guess if the player is standing on the ground, a half-block or next to a ladder
boolean onGroundFrom = playerIsOnGround(from.getWorld(), fromValues, from);
boolean onGroundTo = playerIsOnGround(from.getWorld(), toValues, to);
// Both locations seem to be on solid ground or at a ladder
if(onGroundFrom && onGroundTo)
{
// reset jumping
data.movingJumpPhase = 0;
// Check if the player isn't 'walking' up unrealistically far in one step
// Finally found out why this can happen:
// If a player runs into a wall at an angle from above, the game tries to
// If a player runs into a wall, the game tries to
// place him above the block he bumped into, by placing him 0.5 m above
// the target block
if(!(to.getY() - from.getY() < jumpingPhases[data.movingJumpPhase])) {
if(!(to.getY() - from.getY() < jumpingPhases[0])) {
double offset = (to.getY() - from.getY()) - jumpingPhases[data.movingJumpPhase];
double offset = (to.getY() - from.getY()) - jumpingPhases[0];
if(offset > 2D) vl = max(vl, Level.SEVERE);
else if(offset > 1D) vl = max(vl, Level.WARNING);
else if(offset > 0.5D) vl = max(vl, Level.WARNING);
else vl = max(vl, Level.INFO);
}
else
{
// reset jumping
data.movingJumpPhase = 0;
data.movingSetBackPoint = event.getTo().clone();
}
}
// player is starting to jump (or starting to fall down somewhere)
else if(onGroundFrom && !onGroundTo)
{
// reset jumping
data.movingJumpPhase = 0;
// Check if player isn't jumping too high
if(!(to.getY() - from.getY() < jumpingPhases[data.movingJumpPhase])) {
if(!(to.getY() - from.getY() < jumpingPhases[0])) {
double offset = (to.getY() - from.getY()) - jumpingPhases[data.movingJumpPhase];
double offset = (to.getY() - from.getY()) - jumpingPhases[0];
if(offset > 2D) vl = max(vl, Level.SEVERE);
else if(offset > 1D) vl = max(vl, Level.WARNING);
else if(offset > 0.5D) vl = max(vl, Level.WARNING);
else vl = max(vl, Level.INFO);
}
else if(to.getY() <= from.getY()) {
// Very special case if running over a cliff and then immediately jumping.
// Some sort of "air jump", MC allows it, so we have to do so too.
else {
// Setup next phase of the jump
data.movingJumpPhase = 1;
data.movingSetBackPoint = event.getFrom().clone();
}
else data.movingJumpPhase++; // Setup next phase of the jump
}
// player is probably landing somewhere
else if(!onGroundFrom && onGroundTo)
{
// Check if player isn't landing to high (sounds weird, but has its use)
if(!(to.getY() - from.getY() < jumpingPhases[data.movingJumpPhase])) {
if(!(to.getY() - from.getY() < Math.max(jumpingPhases[data.movingJumpPhase], 0D))) {
double offset = (to.getY() - from.getY()) - jumpingPhases[data.movingJumpPhase];
double offset = (to.getY() - from.getY()) - Math.max(jumpingPhases[data.movingJumpPhase], 0D);
if(offset > 2D) vl = max(vl, Level.SEVERE);
else if(offset > 1D) vl = max(vl, Level.WARNING);
else if(offset > 0.5D) vl = max(vl, Level.WARNING);
else vl = max(vl, Level.INFO);
}
else {
data.movingJumpPhase = 0; // He is on ground now, so reset the jump
data.movingSetBackPoint = event.getTo().clone();
}
}
// Player is moving through air (during jumping, falling)
else {
// May also be at the very edge of a platform (I seem to not be able to reliably tell if that's the case)
if(!(to.getY() - from.getY() < jumpingPhases[data.movingJumpPhase])) {
if(!(to.getY() - from.getY() < jumpingPhases[data.movingJumpPhase]))
{
double offset = (to.getY() - from.getY()) - jumpingPhases[data.movingJumpPhase];
if(offset > 2D) vl = max(vl, Level.SEVERE);
else if(offset > 1D) vl = max(vl, Level.WARNING);
else vl = max(vl, Level.INFO);
}
else {
data.movingJumpPhase++; // Enter next phase of the flight
// Setback point stays the same
}
}
// do a security check on the jumping phase, such that we don't get
@ -249,20 +256,19 @@ public class MovingCheck {
data.movingJumpPhase = jumpingPhases.length - 1;
}
if(vl == null) {
if(vl == null && (onGroundFrom || onGroundTo)) {
legitimateMove(data, event);
}
else {
else if(vl != null) {
data.movingLegitMovesInARow = 0;
String actions = null;
boolean log = true;
// If it is the first violation, store the "from" location for potential later use
if(data.movingSetBackPoint == null) {
data.movingSetBackPoint = event.getFrom().clone();
}
// Find out with what actions to treat the violation(s)
if(Level.INFO.equals(vl)) {
data.movingMinorViolationsInARow++;
actions = NoCheatConfiguration.movingActionMinor;
@ -323,6 +329,13 @@ public class MovingCheck {
protected static void legitimateMove(NoCheatData data, PlayerMoveEvent event) {
data.movingLegitMovesInARow++;
if(data.movingLegitMovesInARow > 40) {
data.movingLegitMovesInARow = 0;
// Give some additional logs about now ending violations
if(data.movingHeavyViolationsInARow > 0) {
NoCheatPlugin.logAction(NoCheatConfiguration.movingActionHeavy, "Moving violation ended: "+event.getPlayer().getName() + " total Events: "+ data.movingHeavyViolationsInARow);
@ -338,8 +351,7 @@ public class MovingCheck {
}
data.movingMinorViolationsInARow = 0;
data.movingSetBackPoint = null;
}
}
private static Level max(Level l1, Level l2) {
@ -361,13 +373,10 @@ public class MovingCheck {
// Still not a perfect solution. After resetting a player his vertical momentum gets lost
// Therefore we can't expect him to fall big distances in his next move, therefore we have to
// set his flying phase to something he can work with.
if(data.movingJumpPhase > 7) {
data.movingJumpPhase = 7;
}
data.movingJumpPhase = 0;
// If we have stored a location for the player, we put him back there
if(data.movingSetBackPoint != null) {
// Lets try it that way. Maybe now people don't "disappear" any longer
event.setFrom(data.movingSetBackPoint);
event.setTo(data.movingSetBackPoint);
@ -443,4 +452,20 @@ public class MovingCheck {
int i = (int)d;
return d > (double)i ? i : i - 1;
}
public static int lowerBorder(double d1) {
double floor = Math.floor(d1);
double d4 = (d1 - floor) - magic;
//System.out.println(d4);
return (int) (floor + d4);
}
public static int upperBorder(double d1) {
double floor = Math.floor(d1);
double d4 = (d1 - floor) - magic2;
//System.out.println(d4);
int tmp = (int) (floor - d4);
return tmp < floor ? tmp + 2 : (int)floor ;
}
}