[BLEEDING] Split off untracked moves. Elaborate on slime blocks.

MISSING:
* Micro move onto ground, fall distance resets before sf check is run.

Done:
* Split PlayerMoveEvent processing to from -> loc + from -> to. Just if
from isn't the same coordinates as player.getLocation. This
reduces the complexity of workarounds.
* You do take fall damage falling onto slime blocks while sneaking.
* Queue bounce effect, only if the move is valid. Skip NoFall then.
* Apply bounce effect once moving up, to allow overriding.
* Cover more odd cases.

Unrelated:
* Use data.debug instead of cc.debug.
This commit is contained in:
asofold 2015-10-20 01:36:22 +02:00
parent 537b387fbf
commit 8de7907522
10 changed files with 299 additions and 203 deletions

View File

@ -74,7 +74,7 @@ public class SoundDistance extends BaseAdapter {
final Location loc = player.getLocation(useLoc);
final StructureModifier<Integer> ints = packetContainer.getIntegers();
final double dSq = TrigUtil.distanceSquared(ints.read(0) / 8, ints.read(2) / 8, loc.getX(), loc.getZ());
// if (cc.debug) {
// if (data.debug) {
// NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, player.getName() + " SoundDistance(" + soundName + "): " + StringUtil.fdec1.format(Math.sqrt(dSq)));
// }
if (dSq > cc.soundDistanceSq) {

View File

@ -152,7 +152,7 @@ public class CreativeFly extends Check {
final double result = Math.max(0.0, resultH) + Math.max(0D, resultV);
if (cc.debug) {
if (data.debug) {
outpuDebugMove(player, hDistance, limitH, yDistance, limitV, data);
}

View File

@ -80,8 +80,9 @@ public class MovingConfig extends ACheckConfig {
public static final double Y_ON_GROUND_MIN = 0.00001;
public static final double Y_ON_GROUND_MAX = 0.0626;
// TODO: Model workarounds as lost ground ?
public static final double Y_ON_GROUND_DEFAULT = 0.016; // TODO: Jumping upwards while placing blocks (otherwise use MIN).
// TODO: Model workarounds as lost ground, use Y_ON_GROUND_MIN?
public static final double Y_ON_GROUND_DEFAULT = 0.016; // Jump upwards, while placing blocks.
// public static final double Y_ON_GROUND_DEFAULT = 0.029; // Bounce off slime blocks.
public final boolean ignoreCreative;

View File

@ -100,7 +100,7 @@ public class MovingData extends ACheckData {
* TODO: Test, might be better ground.
*/
private static final LiftOffEnvelope defaultLiftOffEnvelope = LiftOffEnvelope.NO_JUMP;
/** Tolerance value for using vertical velocity (the client sends different values than received with fight damage). */
private static final double TOL_VVEL = 0.0625;
@ -134,6 +134,9 @@ public class MovingData extends ACheckData {
/** Only used during processing, to keep track of sub-checks using velocity. Reset in velocityTick, before checks run. */
public SimpleEntry verVelUsed = null;
/** Compatibility entry for bouncing of slime blocks and the like. */
public SimpleEntry verticalBounce = null;
/** Tick at which walk/fly speeds got changed last time. */
public int speedTick = 0;
public float walkSpeed = 0.0f;
@ -267,6 +270,7 @@ public class MovingData extends ACheckData {
vehicleConsistency = MoveConsistency.INCONSISTENT;
lastFrictionHorizontal = lastFrictionVertical = 0.0;
verVelUsed = null;
verticalBounce = null;
}
/**
@ -300,6 +304,7 @@ public class MovingData extends ACheckData {
removeAllVelocity();
vehicleConsistency = MoveConsistency.INCONSISTENT; // Not entirely sure here.
lastFrictionHorizontal = lastFrictionVertical = 0.0;
verticalBounce = null;
}
/**
@ -311,6 +316,7 @@ public class MovingData extends ACheckData {
lastYDist = lastHDist = Double.MAX_VALUE;
toWasReset = false;
fromWasReset = false;
verticalBounce = null;
// Remember where we send the player to.
setTeleported(loc);
// TODO: sfHoverTicks ?
@ -366,6 +372,7 @@ public class MovingData extends ACheckData {
sfLowJump = false;
liftOffEnvelope = defaultLiftOffEnvelope;
lastFrictionHorizontal = lastFrictionVertical = 0.0;
verticalBounce = null;
// TODO: other buffers ?
// No reset of vehicleConsistency.
}
@ -616,6 +623,10 @@ public class MovingData extends ACheckData {
}
public void prependVerticalVelocity(final SimpleEntry entry) {
verVel.addToFront(entry);
}
public void addVerticalVelocity(final SimpleEntry entry) {
verVel.add(entry);
}
@ -982,4 +993,14 @@ public class MovingData extends ACheckData {
sfDirty = true;
}
public void useVerticalBounce(final Player player) {
// CHEATING: Ensure fall distance is reset.
player.setFallDistance(0f);
noFallMaxY = 0.0;
noFallFallDistance = 0f;
noFallSkipAirCheck = true;
prependVerticalVelocity(verticalBounce);
verticalBounce = null;
}
}

View File

@ -272,7 +272,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
data.prepareSetBack(target); // Should be enough. | new Location(target.getWorld(), target.getX(), target.getY(), target.getZ(), target.getYaw(), target.getPitch());
player.teleport(target, TeleportCause.PLUGIN);// TODO: schedule / other measures ?
}
else{
else {
// Reset bed ...
CombinedData.getData(player).wasInBed = false;
}
@ -335,8 +335,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
final Player player = event.getPlayer();
// Store the event for monitor level checks.
final String playerName = player.getName();
processingEvents.put(playerName, event);
processingEvents.put(player.getName(), event);
final MovingData data = MovingData.getData(player);
@ -397,11 +396,66 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
}
// newTo should be null here.
// Fire one or two moves here.
final Location loc = player.getLocation(useLoc);
final MovingConfig cc = MovingConfig.getConfig(player);
final MoveInfo moveInfo = useMoveInfo();
if (TrigUtil.isSamePos(from, loc)
|| TrigUtil.isSamePos(loc, data.fromX, data.fromY, data.fromZ)
// Could also be other envelopes (0.9 velocity upwards), too tedious to research.
//&& data.lastYDist < -SurvivalFly.GRAVITY_MIN && data.lastYDist > -SurvivalFly.GRAVITY_MAX - SurvivalFly.GRAVITY_MIN
) {
// Fire move from -> to
// (Special case: Location has not been updated last moving event.)
moveInfo.set(player, from, to, cc.yOnGround);
checkPlayerMove(player, from, to, false, moveInfo, data, cc, event);
}
else {
// Split into two moves.
// 1. Process from -> loc.
if (data.debug) {
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, player.getName() + " Split move 1 (from -> loc):");
}
moveInfo.set(player, from, loc, cc.yOnGround);
if (!checkPlayerMove(player, from, loc, true, moveInfo, data, cc, event) && processingEvents.containsKey(event)) {
// Between -> set data accordingly (compare: onPlayerMoveMonitor).
onMoveMonitorNotCancelled(player, from, loc, System.currentTimeMillis(), TickTask.getTick(), CombinedData.getData(player), data);
data.joinOrRespawn = false;
// 2. Process loc -> to.
if (data.debug) {
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, player.getName() + " Split move 2 (loc -> to):");
}
moveInfo.set(player, loc, to, cc.yOnGround);
checkPlayerMove(player, loc, to, false, moveInfo, data, cc, event);
}
}
// Cleanup.
data.joinOrRespawn = false;
returnMoveInfo(moveInfo);
useLoc.setWorld(null);
}
/**
*
* @param player
* @param from
* @param to
* @param mightBeMultipleMoves
* @param moveInfo
* @param data
* @param cc
* @param event
* @return If cancelled/done, i.e. not to process further split moves.
*/
private boolean checkPlayerMove(final Player player, final Location from, final Location to,
final boolean mightBeMultipleMoves, final MoveInfo moveInfo, final MovingData data, final MovingConfig cc,
final PlayerMoveEvent event) {
Location newTo = null;
// TODO: Order this to above "early return"?
// Set up data / caching.
final MoveInfo moveInfo = useMoveInfo();
final MovingConfig cc = MovingConfig.getConfig(player);
moveInfo.set(player, from, to, cc.yOnGround);
// TODO: Data resetting above ?
data.noFallAssumeGround = false;
data.resetTeleported();
@ -413,9 +467,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
if ((moveInfo.from.hasIllegalCoords() || moveInfo.to.hasIllegalCoords()) ||
!cc.ignoreStance && (moveInfo.from.hasIllegalStance() || moveInfo.to.hasIllegalStance())) {
MovingUtil.handleIllegalMove(event, player, data, cc);
moveInfo.cleanup();
parkedInfo.add(moveInfo);
return;
return true;
}
{
@ -441,7 +493,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
}
}
final String playerName = player.getName(); // TODO: Could switch to UUID here (needs more changes).
// Check for location consistency.
if (cc.enforceLocation && playersEnforce.contains(playerName)) {
@ -516,35 +568,43 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
data.adjustFlySpeed(player.getFlySpeed(), tick, cc.speedGrace);
data.adjustWalkSpeed(player.getWalkSpeed(), tick, cc.speedGrace);
}
else{
else {
checkCf = checkSf = false;
}
boolean checkNf = true;
boolean verticalBounce = false;
if (checkSf || checkCf) {
// Check jumping on things like slime blocks.
// The center of the player must be above the block.
// TODO: Apply effects later, if the move has not been not cancelled.
if (to.getY() < from.getY() && player.getFallDistance() > 1f
if (to.getY() < from.getY()
&& (BlockProperties.getBlockFlags(pTo.getTypeIdBelow()) & BlockProperties.F_BOUNCE25) != 0L
&& to.getY() - to.getBlockY() <= Math.max(cc.yOnGround, cc.noFallyOnGround)) {
&& !survivalFly.isReallySneaking(player)
&& (to.getY() - to.getBlockY() <= Math.max(cc.yOnGround, cc.noFallyOnGround) && player.getFallDistance() > 1f
|| to.getY() - to.getBlockY() < 0.286 && to.getY() - from.getY() > -0.5 && to.getY() - from.getY() < -SurvivalFly.GRAVITY_MAX - SurvivalFly.GRAVITY_SPAN && !pTo.isOnGround())
) {
// Prepare bounce: The center of the player must be above the block.
// TODO: Check other side conditions (fluids, web, max. distance to the block top (!))
// Apply changes to NoFall and other.
processTrampoline(player, pFrom, pTo, data, cc);
verticalBounce = true;
// Skip NoFall.
checkNf = false;
}
else if (data.verticalBounce != null) {
if (to.getY() > from.getY()) {
// Apply bounce.
checkNf = false;
data.useVerticalBounce(player);
} else {
data.verticalBounce = null;
}
}
}
// The players location.
final Location loc = (cc.passableCheck || checkNf || checkSf) ? player.getLocation(moveInfo.useLoc) : null;
// Check passable first to prevent set-back override.
// TODO: Redesign to set set-backs later (queue + invalidate).
boolean mightSkipNoFall = false; // If to skip nofall check (mainly on violation of other checks).
if (newTo == null && cc.passableCheck && player.getGameMode() != BridgeMisc.GAME_MODE_SPECTATOR && !NCPExemptionManager.isExempted(player, CheckType.MOVING_PASSABLE) && !player.hasPermission(Permissions.MOVING_PASSABLE)) {
// Passable is checked first to get the original set-back locations from the other checks, if needed.
newTo = passable.check(player, loc, pFrom, pTo, data, cc);
newTo = passable.check(player, pFrom, pTo, data, cc);
if (newTo != null) {
// Check if to skip the nofall check.
mightSkipNoFall = true;
@ -565,7 +625,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// Sets all properties, but only once.
pTo.prepare(pFrom);
}
else{
else {
// Might collect block flags for small distances with the containing bounds for both.
pTo.collectBlockFlags(maxYNoFall);
}
@ -573,7 +633,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// Actual check.
if (newTo == null) {
// Only check if passable has not already set back.
newTo = survivalFly.check(player, pFrom, loc, pTo, isSamePos, data, cc, time);
newTo = survivalFly.check(player, pFrom, pTo, isSamePos, data, cc, time);
}
// Only check NoFall, if not already vetoed.
if (checkNf) {
@ -587,15 +647,15 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
hoverTicks.add(playerName);
data.sfHoverTicks = 0;
}
else{
else {
data.sfHoverTicks = -1;
}
// NoFall.
if (checkNf) {
noFall.check(player, loc, pFrom, pTo, data, cc);
noFall.check(player, pFrom, pTo, data, cc);
}
}
else{
else {
if (checkNf && cc.sfSetBackPolicyFallDamage) {
if (noFall.estimateDamage(player, from.getY(), data) < 1.0) {
// TODO: Consider making this / damage amount configurable.
@ -609,7 +669,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
}
if (!mightSkipNoFall && (!pTo.isResetCond() || !pFrom.isResetCond())) {
// (Don't deal damage where no fall damage is possible.)
noFall.checkDamage(player, data, Math.min(Math.min(from.getY(), to.getY()), loc.getY()));
noFall.checkDamage(player, data, Math.min(from.getY(), to.getY()));
}
}
}
@ -622,7 +682,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
data.sfHoverTicks = -1;
data.sfLowJump = false;
}
else{
else {
// No fly checking :(.
data.clearFlyData();
}
@ -649,58 +709,50 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// Set positions.
// TODO: Consider setting in Monitor (concept missing for changing coordinates, could double-check).
data.setPositions(from, to);
// Bounce effects.
if (verticalBounce) {
processBounce(player, pFrom, pTo, data, cc);
}
return false;
}
else {
// Set-back handling.
onSetBack(player, event, newTo, data, cc);
return true;
}
// Cleanup.
data.joinOrRespawn = false;
returnMoveInfo(moveInfo);
}
/**
* Adjust data to allow bouncing back and/or removing fall damage.<br>
* yDistance is < 0, the middle of the player is above a slime block (to) + on ground.
* yDistance is < 0, the middle of the player is above a slime block (to) +
* on ground.
*
* @param player
* @param from
* @param to
* @param data
* @param cc
*/
private void processTrampoline(final Player player, final PlayerLocation from, final PlayerLocation to, final MovingData data, final MovingConfig cc) {
// CHEATING: Add velocity.
if (!survivalFly.isReallySneaking(player)) {
final double fallDistance;
if (noFall.isEnabled(player, cc)) {
// (NoFall will not be checked, if this method is called.)
if (data.noFallMaxY >= from.getY() ) {
fallDistance = data.noFallMaxY - to.getY();
} else {
fallDistance = from.getY() - to.getY();
}
private void processBounce(final Player player, final PlayerLocation from, final PlayerLocation to, final MovingData data, final MovingConfig cc) {
// CHEATING: Prepare velocity.
final double fallDistance;
if (noFall.isEnabled(player, cc)) {
// (NoFall will not be checked, if this method is called.)
if (data.noFallMaxY >= from.getY() ) {
fallDistance = data.noFallMaxY - to.getY();
} else {
fallDistance = player.getFallDistance() + from.getY() - to.getY();
fallDistance = from.getY() - to.getY();
}
final double effect = Math.min(3.14, Math.sqrt(fallDistance) / 3.3 + SurvivalFly.GRAVITY_MAX); // Ancient Greek technology with gravity added.
// (Actually observed max. is near 3.5.) TODO: Why 3.14 then?
if (cc.debug) {
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, player.getName() + " Trampoline effect (dY=" + fallDistance + "): " + effect);
}
data.addVerticalVelocity(new SimpleEntry(effect, 2)); // Not logged at present.
} else {
if (cc.debug) {
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, player.getName() + " Trampoline effect (sneaking).");
}
fallDistance = player.getFallDistance() + from.getY() - to.getY();
}
final double effect = Math.min(3.14, Math.sqrt(fallDistance) / 3.3 + SurvivalFly.GRAVITY_MAX); // Ancient Greek technology with gravity added.
// (Actually observed max. is near 3.5.) TODO: Why 3.14 then?
if (data.debug) {
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, player.getName() + " Bounce effect (dY=" + fallDistance + "): " + effect);
}
// CHEATING: Remove fall distance:
player.setFallDistance(0f);
// (Ignore if NoFall is enabled or not here.)
data.noFallFallDistance = 0f;
data.noFallMaxY = 0.0;
data.noFallSkipAirCheck = true;
// (After this the NoFall check should be skipped.)
data.verticalBounce = new SimpleEntry(effect, 1);
}
/**
@ -811,44 +863,62 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
return;
}
if (player.isDead() || player.isSleeping()) return;
if (player.isDead() || player.isSleeping()) {
return;
}
// Feed combined check.
final CombinedData data = CombinedData.getData(player);
data.lastMoveTime = now; // TODO: Evaluate moving this to MovingData !?
final Location from = event.getFrom();
final String fromWorldName = from.getWorld().getName();
// Feed yawrate and reset moving data positions if necessary.
final MovingData mData = MovingData.getData(player);
final long time = TickTask.getTick();
final long tick = TickTask.getTick();
if (!event.isCancelled()) {
final Location to = event.getTo();
final String toWorldName = to.getWorld().getName();
Combined.feedYawRate(player, to.getYaw(), now, toWorldName, data);
// TODO: maybe even not count vehicles at all ?
if (player.isInsideVehicle()) {
// TODO: refine (!).
final Location ref = player.getVehicle().getLocation(useLoc);
mData.resetPositions(ref); // TODO: Consider using to and intercept cheat attempts in another way.
useLoc.setWorld(null);
mData.updateTrace(player, to, time); // TODO: Can you become invincible by sending special moves?
}
else if (!fromWorldName.equals(toWorldName)) {
mData.resetPositions(to);
mData.resetTrace(player, to, time);
}
else{
mData.setTo(to); // Called on lowest too.
mData.updateTrace(player, to, time);
}
final Location pLoc = player.getLocation();
onMoveMonitorNotCancelled(player, TrigUtil.isSamePosAndLook(pLoc, from) ? from : pLoc, event.getTo(), now, tick, data, mData);
useLoc.setWorld(null);
}
else {
data.lastMoveTime = now; // TODO: Evaluate moving this to MovingData !?
// TODO: teleported + other resetting ?
Combined.feedYawRate(player, from.getYaw(), now, fromWorldName, data);
Combined.feedYawRate(player, from.getYaw(), now, from.getWorld().getName(), data);
mData.resetPositions(from);
mData.resetTrace(player, from, time); // TODO: Should probably leave this to the teleport event!
mData.resetTrace(player, from, tick); // TODO: Should probably leave this to the teleport event!
}
}
/**
* Overrides useLoc if in vehicle.
* @param player
* @param from
* @param to
* @param now
* @param tick
* @param data
* @param mData
*/
private void onMoveMonitorNotCancelled(final Player player, final Location from, final Location to, final long now, final long tick, final CombinedData data, final MovingData mData) {
data.lastMoveTime = now; // TODO: Evaluate moving this to MovingData !?
final String toWorldName = to.getWorld().getName();
Combined.feedYawRate(player, to.getYaw(), now, toWorldName, data);
// TODO: maybe even not count vehicles at all ?
if (player.isInsideVehicle()) {
// TODO: refine (!).
final Location ref = player.getVehicle().getLocation(useLoc);
mData.resetPositions(ref); // TODO: Consider using to and intercept cheat attempts in another way.
useLoc.setWorld(null);
mData.updateTrace(player, to, tick); // TODO: Can you become invincible by sending special moves?
}
else if (!from.getWorld().getName().equals(toWorldName)) {
mData.resetPositions(to);
mData.resetTrace(player, to, tick);
}
else {
mData.setTo(to); // Called on lowest too.
mData.updateTrace(player, to, tick);
}
}
@ -875,11 +945,11 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
public void onPlayerDeath(final PlayerDeathEvent event) {
final Player player = event.getEntity();
final MovingData data = MovingData.getData(player);
final MovingConfig cc = MovingConfig.getConfig(player);
//final MovingConfig cc = MovingConfig.getConfig(player);
data.clearFlyData();
data.clearMorePacketsData();
data.setSetBack(player.getLocation(useLoc)); // TODO: Monitor this change (!).
if (cc.debug) {
if (data.debug) {
// Log location.
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, player.getName() + " death: " + player.getLocation(useLoc));
}
@ -918,7 +988,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
event.setFrom(teleported);
ref = teleported;
}
else{
else {
// Not cancelled but NCP teleport.
ref = to;
}
@ -964,7 +1034,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// Not check on-ground: Check the second throw.
cancel = true;
}
else{
else {
// pass = true;
}
}
@ -996,7 +1066,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
event.setTo(ref);
adjustLiftOffEnvelope(player, ref, data, cc);
}
else{
else {
ref = from; // Player.getLocation ?
event.setCancelled(true);
}
@ -1017,7 +1087,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// });
// }
}
else{
else {
// "real" teleport
ref = to;
double fallDistance = data.noFallFallDistance;
@ -1051,7 +1121,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, player.getName() + " TP" + (smallRange ? " (small-range)" : "") + (cancel ? " (cancelled)" : "") + ": " + to);
}
}
else{
else {
// Cancelled, not a set back, ignore it, basically.
// Better reset teleported (compatibility). Might have drawbacks.
data.resetTeleported();
@ -1180,7 +1250,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// If the player is handled by the more packets vehicle check, execute it.
newTo = morePacketsVehicle.check(player, from, to, data, cc);
}
else{
else {
// Otherwise we need to clear their data.
data.clearMorePacketsData();
}
@ -1238,7 +1308,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
allowReset = false;
}
}
else{
else {
// Legitimate damage: clear accounting data.
data.vDistAcc.clear();
// TODO: Also reset other properties.
@ -1265,7 +1335,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// Normal fall damage, reset data.
data.clearNoFallData();
}
else{
else {
// Minecraft/NCP bug or cheating.
// (Do not cancel the event, otherwise: "moved too quickly exploit".)
if (cc.noFallViolationReset) {
@ -1371,7 +1441,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// if (LocUtil.needsDirectionCorrection(useLoc.getYaw(), useLoc.getPitch())) {
// DataManager.getPlayerData(player).task.correctDirection();
// }
if (cc.debug) {
if (data.debug) {
// Log location.
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, player.getName() + " " + tag + ": " + loc);
}
@ -1393,7 +1463,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
data.sfHoverLoginTicks = cc.sfHoverLoginTicks;
hoverTicks.add(player.getName());
}
else{
else {
data.sfHoverLoginTicks = 0;
data.sfHoverTicks = -1;
}
@ -1712,7 +1782,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
res = true;
data.sfHoverTicks = 0;
}
else{
else {
if (data.sfHoverTicks > cc.sfHoverTicks) {
// Re-Check if survivalfly can apply at all.
if (MovingUtil.shouldCheckSurvivalFly(player, data, cc)) {
@ -1721,7 +1791,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
res = false;
data.sfHoverTicks = 0;
}
else{
else {
// Reset hover ticks and check next period.
res = false;
data.sfHoverTicks = 0;

View File

@ -122,7 +122,7 @@ public class NoFall extends Check {
* @param to
* the to
*/
public void check(final Player player, final Location loc, final PlayerLocation from, final PlayerLocation to, final MovingData data, final MovingConfig cc) {
public void check(final Player player, final PlayerLocation from, final PlayerLocation to, final MovingData data, final MovingConfig cc) {
final double fromY = from.getY();
final double toY = to.getY();
@ -151,8 +151,7 @@ public class NoFall extends Check {
// TODO: early returns (...)
final double pY = loc.getY();
final double minY = Math.min(fromY, Math.min(toY, pY));
final double minY = Math.min(fromY, toY);
if (fromReset) {
// Just reset.
@ -190,7 +189,7 @@ public class NoFall extends Check {
// Set reference y for nofall (always).
// TODO: Consider setting this before handleOnGround (at least for resetTo).
data.noFallMaxY = Math.max(Math.max(fromY, Math.max(toY, pY)), data.noFallMaxY);
data.noFallMaxY = Math.max(Math.max(fromY, toY), data.noFallMaxY);
// TODO: fall distance might be behind (!)
// TODO: should be the data.noFallMaxY be counted in ?

View File

@ -26,7 +26,7 @@ public class Passable extends Check {
rayTracing.setMaxSteps(60); // TODO: Configurable ?
}
public Location check(final Player player, Location loc, final PlayerLocation from, final PlayerLocation to, final MovingData data, final MovingConfig cc)
public Location check(final Player player, final PlayerLocation from, final PlayerLocation to, final MovingData data, final MovingConfig cc)
{
// TODO: if (!from.isSameCoords(loc)) {...check passable for loc -> from !?... + sf etc too?}
// TODO: Future: Account for the players bounding box? [test very-strict setting for at least the end points...]
@ -80,20 +80,14 @@ public class Passable extends Check {
data.passableVL *= 0.99;
return null;
} else {
return potentialViolation(player, loc, from, to, manhattan, tags, data, cc);
return potentialViolation(player, from, to, manhattan, tags, data, cc);
}
}
private Location potentialViolation(final Player player, final Location loc, final PlayerLocation from, final PlayerLocation to, final int manhattan, String tags, final MovingData data, final MovingConfig cc) {
private Location potentialViolation(final Player player, final PlayerLocation from, final PlayerLocation to, final int manhattan, String tags, final MovingData data, final MovingConfig cc) {
// Moving into a block, possibly a violation.
// Check the players location if different from others.
// (It provides a better set-back for some exploits.)
final int lbX = loc.getBlockX();
final int lbY = loc.getBlockY();
final int lbZ = loc.getBlockZ();
Location setBackLoc = null; // Alternative to from.getLocation().
// First check if the player is moving from a passable location.
// If not, the move might still be allowed, if moving inside of the same block, or from and to have head position passable.
if (from.isPassable()) {
@ -107,19 +101,12 @@ public class Passable extends Check {
}
// From should be the set-back.
tags += "into";
} else if (BlockProperties.isPassable(from.getBlockCache(), loc.getX(), loc.getY(), loc.getZ(), from.getTypeId(lbX, lbY, lbZ))) {
// Keep loc, because it it is passable.
tags += "into_shift";
setBackLoc = loc;
}
// } else if (BlockProperties.isPassableExact(from.getBlockCache(), loc.getX(), loc.getY(), loc.getZ(), from.getTypeId(lbX, lbY, lbZ))) {
// (Mind that this can be the case on the same block theoretically.)
// Keep loc as set-back.
// }
else if (!from.isSameBlock(lbX, lbY, lbZ)) {
// Both loc and from are not passable. Use from as set.back (earliest).
tags += "cross_shift";
}
else if (manhattan == 1 && to.isBlockAbove(from) && BlockProperties.isPassable(from.getBlockCache(), from.getX(), from.getY() + player.getEyeHeight(), from.getZ(), from.getTypeId(from.getBlockX(), Location.locToBlock(from.getY() + player.getEyeHeight()), from.getBlockZ()))) {
// else if (to.isBlockAbove(from) && BlockProperties.isPassableExact(from.getBlockCache(), from.getX(), from.getY() + player.getEyeHeight(), from.getZ(), from.getTypeId(from.getBlockX(), Location.locToBlock(from.getY() + player.getEyeHeight()), from.getBlockZ()))) {
// Allow the move up if the head is free.
@ -135,24 +122,13 @@ public class Passable extends Check {
return null;
}
// Discard inconsistent locations.
// TODO: Might get rid of using the in-between loc - needs use-case checking.
if (setBackLoc != null && (TrigUtil.distance(from, to) > 0.75 || TrigUtil.distance(from, setBackLoc) > 0.125)) {
setBackLoc = null;
}
Location setBackLoc = null; // Alternative to from.getLocation().
// Prefer the set-back location from the data.
if (data.hasSetBack()) {
// TODO: Review or make configurable.
final Location ref = data.getSetBack(to);
if (BlockProperties.isPassable(from.getBlockCache(), ref) || setBackLoc == null || TrigUtil.distance(from, setBackLoc) > 0.13) {
// if (BlockProperties.isPassableExact(from.getBlockCache(), ref)) {
setBackLoc = ref;
if (data.debug) {
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, player.getName() + " Using set-back location for passable.");
}
} else if (data.debug) {
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, player.getName() + " Ignoring set-back for passable.");
setBackLoc = data.getSetBack(to);;
if (data.debug) {
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, player.getName() + " Using set-back location for passable.");
}
}

View File

@ -112,7 +112,7 @@ public class SurvivalFly extends Check {
* @param isSamePos
* @return the location
*/
public Location check(final Player player, final PlayerLocation from, final Location loc, final PlayerLocation to, final boolean isSamePos, final MovingData data, final MovingConfig cc, final long now) {
public Location check(final Player player, final PlayerLocation from, final PlayerLocation to, final boolean isSamePos, final MovingData data, final MovingConfig cc, final long now) {
tags.clear();
// Calculate some distances.
@ -144,7 +144,7 @@ public class SurvivalFly extends Check {
(from.isOnGround() || from.isResetCond())) {
// TODO: Move most to a method?
// TODO: Is a margin needed for from.isOnGround()? [bukkitapionly]
if (cc.debug) {
if (data.debug) {
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, player.getName() + " SurvivalFly\nAdjust set-back after join/respawn: " + from.getLocation());
}
data.setSetBack(from);
@ -214,7 +214,7 @@ public class SurvivalFly extends Check {
// TODO: This isn't correct, needs redesign.
if (data.lastHDist != Double.MAX_VALUE && data.lastHDist > 0.0 && data.lastYDist < -0.3) {
// Note that to is not on ground either.
resetFrom = lostGroundStill(player, from, loc, to, hDistance, yDistance, sprinting, data, cc);
resetFrom = lostGroundStill(player, from, to, hDistance, yDistance, sprinting, data, cc);
} else {
resetFrom = false;
}
@ -224,7 +224,7 @@ public class SurvivalFly extends Check {
// TODO: More refined conditions possible ?
// TODO: Consider if (!resetTo) ?
// Check lost-ground workarounds.
resetFrom = lostGround(player, from, loc, to, hDistance, yDistance, sprinting, data, cc);
resetFrom = lostGround(player, from, to, hDistance, yDistance, sprinting, data, cc);
// Note: if not setting resetFrom, other places have to check assumeGround...
}
@ -381,7 +381,9 @@ public class SurvivalFly extends Check {
final double result = (Math.max(hDistanceAboveLimit, 0D) + Math.max(vDistanceAboveLimit, 0D)) * 100D;
if (result > 0D) {
final Location vLoc = handleViolation(now, result, player, from, to, data, cc);
if (vLoc != null) return vLoc;
if (vLoc != null) {
return vLoc;
}
}
else {
// Slowly reduce the level with each event, if violations have not recently happened.
@ -690,7 +692,7 @@ public class SurvivalFly extends Check {
* @param cc
* @return If touching the ground was lost.
*/
private boolean lostGround(final Player player, final PlayerLocation from, final Location loc, final PlayerLocation to, final double hDistance, final double yDistance, final boolean sprinting, final MovingData data, final MovingConfig cc) {
private boolean lostGround(final Player player, final PlayerLocation from, final PlayerLocation to, final double hDistance, final double yDistance, final boolean sprinting, final MovingData data, final MovingConfig cc) {
// TODO: Regroup with appropriate conditions (toOnGround first?).
// TODO: Some workarounds allow step height (0.6 on MC 1.8).
// TODO: yDistance limit does not seem to be appropriate.
@ -698,13 +700,13 @@ public class SurvivalFly extends Check {
// "Mild" Ascending / descending.
//Ascending
if (yDistance >= 0) {
if (lostGroundAscend(player, from, loc, to, hDistance, yDistance, sprinting, data, cc)) {
if (lostGroundAscend(player, from, to, hDistance, yDistance, sprinting, data, cc)) {
return true;
}
}
// Descending.
if (yDistance <= 0) {
if (lostGroundDescend(player, from, loc, to, hDistance, yDistance, sprinting, data, cc)) {
if (lostGroundDescend(player, from, to, hDistance, yDistance, sprinting, data, cc)) {
return true;
}
}
@ -741,6 +743,7 @@ public class SurvivalFly extends Check {
// TODO: Cleanup pending.
final boolean strictVdistRel;
final double maxJumpGain = data.liftOffEnvelope.getMaxJumpGain(data.jumpAmplifier);
final double jumpGainMargin = 0.005; // TODO: Model differently, workarounds where needed. 0.05 interferes with max height vs. velocity (<= 0.47 gain).
if (fallingEnvelope(yDistance, data.lastYDist, 0.0)) {
// Less headache: Always allow falling.
vAllowedDistance = data.lastYDist * FRICTION_MEDIUM_AIR - GRAVITY_MIN; // Upper bound.
@ -753,7 +756,7 @@ public class SurvivalFly extends Check {
} else {
// Code duplication with the absolute limit below.
if (yDistance < 0.0 || yDistance > cc.sfStepHeight || !tags.contains("lostground_couldstep")) {
vAllowedDistance = maxJumpGain + 0.05; // TODO: Margin
vAllowedDistance = maxJumpGain + jumpGainMargin;
} else {
// lostground_couldstep
vAllowedDistance = yDistance;
@ -768,7 +771,7 @@ public class SurvivalFly extends Check {
}
else {
// TODO: Needs more precise confinement + setting set back or distance to ground or estYDist.
vAllowedDistance = maxJumpGain + 0.05; // TODO: Margin
vAllowedDistance = maxJumpGain + jumpGainMargin;
}
strictVdistRel = false;
} else {
@ -821,7 +824,7 @@ public class SurvivalFly extends Check {
else if (oddLiquid(yDistance, yDistDiffEx, maxJumpGain, resetTo, data)) {
// Jump after leaving the liquid near ground.
}
else if (oddGravity(from, yDistance, yDistChange, data)) {
else if (oddGravity(from, to, yDistance, yDistChange, data)) {
// Starting to fall / gravity effects.
}
else if (oddSlope(to, yDistance, maxJumpGain, yDistDiffEx, data)) {
@ -837,7 +840,7 @@ public class SurvivalFly extends Check {
// Allow jumping less high unless within "strict envelope".
// TODO: Extreme anti-jump effects, perhaps.
}
else if (oddGravity(from, yDistance, yDistChange, data)) {
else if (oddGravity(from, to, yDistance, yDistChange, data)) {
// Starting to fall.
}
else if (oddSlope(to, yDistance, maxJumpGain, yDistDiffEx, data)) {
@ -882,7 +885,7 @@ public class SurvivalFly extends Check {
) {
// LIMIT_LIQUID, vDist inversion (!).
}
else if (oddGravity(from, yDistance, yDistChange, data)) {
else if (oddGravity(from, to, yDistance, yDistChange, data)) {
// Starting to fall.
}
else {
@ -1042,7 +1045,7 @@ public class SurvivalFly extends Check {
* @param data
* @return If the condition applies, i.e. if to exempt.
*/
private static boolean oddGravity(final PlayerLocation from, final double yDistance, final double yDistChange, final MovingData data) {
private static boolean oddGravity(final PlayerLocation from, final PlayerLocation to, final double yDistance, final double yDistChange, final MovingData data) {
// TODO: Identify spots only to apply with limited LiftOffEnvelope (some guards got removed before switching to that).
// TODO: Cleanup pending.
// Old condition (normal lift-off envelope).
@ -1069,44 +1072,53 @@ public class SurvivalFly extends Check {
&& yDistance >= -GRAVITY_MAX - GRAVITY_SPAN && yDistance <= GRAVITY_MIN
// Slope with slimes (also near ground without velocityJumpPhase, rather lowjump but not always).
|| data.lastYDist < -GRAVITY_MAX && yDistChange < - GRAVITY_ODD / 2.0 && yDistChange > -GRAVITY_MIN
// Near ground (slime block).
|| data.lastYDist == 0.0 && yDistance < -GRAVITY_ODD / 2.5 && yDistance > -GRAVITY_MIN && to.isOnGround(GRAVITY_MIN)
)
|| data.isVelocityJumpPhase()
&& (
// Near zero inversion with slimes (rather dirty phase).
data.lastYDist > GRAVITY_ODD && data.lastYDist < GRAVITY_MAX + GRAVITY_MIN
&& yDistance <= -data.lastYDist && yDistance > -data.lastYDist - GRAVITY_MAX - GRAVITY_ODD
// Odd mini-decrease with dirty phase (slime).
|| data.lastYDist < -0.204 && yDistance > -0.26
&& yDistChange > -GRAVITY_MIN && yDistChange < -GRAVITY_ODD / 4.0
)
// Jump-effect-specific
// TODO: Jump effect at reduced lift off envelope -> skip this?
|| data.jumpAmplifier > 0 && data.lastYDist < GRAVITY_MAX + GRAVITY_MIN / 2.0 && data.lastYDist > -2.0 * GRAVITY_MAX - 0.5 * GRAVITY_MIN
&& yDistance > -2.0 * GRAVITY_MAX - 2.0 * GRAVITY_MIN && yDistance < GRAVITY_MIN
&& yDistChange < -GRAVITY_SPAN
// Another near 0 yDistance case. TODO: Inaugurate into some more generic envelope.
|| data.lastYDist > -GRAVITY_MAX && data.lastYDist < GRAVITY_MIN && !data.toWasReset
&& yDistance < data.lastYDist - GRAVITY_MIN / 2.0 && yDistance > data.lastYDist - GRAVITY_MAX - 0.5 * GRAVITY_MIN
// Reduced jumping envelope.
|| data.liftOffEnvelope != LiftOffEnvelope.NORMAL
&& (
// Wild-card allow half gravity near 0 yDistance. TODO: Check for removal of included cases elsewhere.
data.lastYDist > -10.0 * GRAVITY_ODD / 2.0 && data.lastYDist < 10.0 * GRAVITY_ODD
&& yDistance < data.lastYDist - GRAVITY_MIN / 2.0 && yDistance > data.lastYDist - GRAVITY_MAX
//
|| data.lastYDist < GRAVITY_MAX + GRAVITY_SPAN && data.lastYDist > GRAVITY_ODD
&& yDistance > 0.4 * GRAVITY_ODD && yDistance - data.lastYDist < -GRAVITY_ODD / 2.0
//
|| data.lastYDist < 0.2 && data.lastYDist >= 0.0 && yDistance > -0.2 && yDistance < 2.0 * GRAVITY_MAX
//
|| data.lastYDist > 0.4 * GRAVITY_ODD && data.lastYDist < GRAVITY_MIN && yDistance == 0.0
// Too small decrease, right after lift off.
|| data.sfJumpPhase == 1 && data.lastYDist > -GRAVITY_ODD && data.lastYDist <= GRAVITY_MAX + GRAVITY_SPAN
&& yDistance - data.lastYDist < 0.0114
// Any leaving liquid and keeping distance once.
|| data.sfJumpPhase == 1
&& Math.abs(yDistance) <= swimBaseSpeedV() && yDistance == data.lastYDist
)
// With velocity.
|| data.isVelocityJumpPhase()
&& (
// Near zero inversion with slimes (rather dirty phase).
data.lastYDist > GRAVITY_ODD && data.lastYDist < GRAVITY_MAX + GRAVITY_MIN
&& yDistance <= -data.lastYDist && yDistance > -data.lastYDist - GRAVITY_MAX - GRAVITY_ODD
// Odd mini-decrease with dirty phase (slime).
|| data.lastYDist < -0.204 && yDistance > -0.26
&& yDistChange > -GRAVITY_MIN && yDistChange < -GRAVITY_ODD / 4.0
// Lot's of decrease near zero TODO: merge later.
|| data.lastYDist < -GRAVITY_ODD && data.lastYDist > -GRAVITY_MIN
&& yDistance > -2.0 * GRAVITY_MAX - 2.0 * GRAVITY_MIN && yDistance < -GRAVITY_MAX
// Odd decrease less near zero.
|| yDistChange > -GRAVITY_MIN && yDistChange < -GRAVITY_ODD
&& data.lastYDist < 0.5 && data.lastYDist > 0.4
)
// Jump-effect-specific
// TODO: Jump effect at reduced lift off envelope -> skip this?
|| data.jumpAmplifier > 0 && data.lastYDist < GRAVITY_MAX + GRAVITY_MIN / 2.0 && data.lastYDist > -2.0 * GRAVITY_MAX - 0.5 * GRAVITY_MIN
&& yDistance > -2.0 * GRAVITY_MAX - 2.0 * GRAVITY_MIN && yDistance < GRAVITY_MIN
&& yDistChange < -GRAVITY_SPAN
// Another near 0 yDistance case. TODO: Inaugurate into some more generic envelope.
|| data.lastYDist > -GRAVITY_MAX && data.lastYDist < GRAVITY_MIN && !data.toWasReset
&& yDistance < data.lastYDist - GRAVITY_MIN / 2.0 && yDistance > data.lastYDist - GRAVITY_MAX - 0.5 * GRAVITY_MIN
// Reduced jumping envelope.
|| data.liftOffEnvelope != LiftOffEnvelope.NORMAL
&& (
// Wild-card allow half gravity near 0 yDistance. TODO: Check for removal of included cases elsewhere.
data.lastYDist > -10.0 * GRAVITY_ODD / 2.0 && data.lastYDist < 10.0 * GRAVITY_ODD
&& yDistance < data.lastYDist - GRAVITY_MIN / 2.0 && yDistance > data.lastYDist - GRAVITY_MAX
//
|| data.lastYDist < GRAVITY_MAX + GRAVITY_SPAN && data.lastYDist > GRAVITY_ODD
&& yDistance > 0.4 * GRAVITY_ODD && yDistance - data.lastYDist < -GRAVITY_ODD / 2.0
//
|| data.lastYDist < 0.2 && data.lastYDist >= 0.0 && yDistance > -0.2 && yDistance < 2.0 * GRAVITY_MAX
//
|| data.lastYDist > 0.4 * GRAVITY_ODD && data.lastYDist < GRAVITY_MIN && yDistance == 0.0
// Too small decrease, right after lift off.
|| data.sfJumpPhase == 1 && data.lastYDist > -GRAVITY_ODD && data.lastYDist <= GRAVITY_MAX + GRAVITY_SPAN
&& yDistance - data.lastYDist < 0.0114
// Any leaving liquid and keeping distance once.
|| data.sfJumpPhase == 1
&& Math.abs(yDistance) <= swimBaseSpeedV() && yDistance == data.lastYDist
)
;
}
@ -1688,7 +1700,7 @@ public class SurvivalFly extends Check {
* @param cc
* @return
*/
private boolean lostGroundAscend(final Player player, final PlayerLocation from, final Location loc, final PlayerLocation to, final double hDistance, final double yDistance, final boolean sprinting, final MovingData data, final MovingConfig cc) {
private boolean lostGroundAscend(final Player player, final PlayerLocation from, final PlayerLocation to, final double hDistance, final double yDistance, final boolean sprinting, final MovingData data, final MovingConfig cc) {
final double setBackYDistance = to.getY() - data.getSetBackY();
// Step height related.
// TODO: Combine / refine preconditions for step height related.
@ -1727,14 +1739,7 @@ public class SurvivalFly extends Check {
}
// Special cases.
if (!from.isSamePos(loc)) {
// Micro-moves: Re-check with loc instead of from.
// TODO: These belong checked as extra moves. The untracked nature of this means potential exploits.
if (lostGroundEdgeAsc(player, from.getBlockCache(), from.getWorld(), loc.getX(), loc.getY(), loc.getZ(), from.getWidth(), from.getyOnGround(), data, "asc3")) {
return true;
}
}
else if (yDistance == 0.0 && data.lastYDist <= -0.23 && (hDistance <= data.lastHDist * 1.1)) {
if (yDistance == 0.0 && data.lastYDist <= -0.23 && (hDistance <= data.lastHDist * 1.1)) {
// Similar to couldstep, with 0 y-distance but slightly above any ground nearby (no micro move!).
// TODO: (hDistance <= data.sfLastHDist || hDistance <= hAllowedDistance)
// TODO: Confining in x/z direction in general: should detect if collided in that direction (then skip the x/z dist <= last time).
@ -1770,7 +1775,7 @@ public class SurvivalFly extends Check {
* @param cc
* @return
*/
private boolean lostGroundStill(final Player player, final PlayerLocation from, final Location loc, final PlayerLocation to, final double hDistance, final double yDistance, final boolean sprinting, final MovingData data, final MovingConfig cc) {
private boolean lostGroundStill(final Player player, final PlayerLocation from, final PlayerLocation to, final double hDistance, final double yDistance, final boolean sprinting, final MovingData data, final MovingConfig cc) {
if (data.lastYDist <= -0.23) {
// TODO: Code duplication with edgeasc5 above.
if (lostGroundEdgeAsc(player, from.getBlockCache(), to.getWorld(), to.getX(), to.getY(), to.getZ(), from.getX(), from.getY(), from.getZ(), hDistance, to.getWidth(), 0.3, data, "asc7")) {
@ -1840,7 +1845,7 @@ public class SurvivalFly extends Check {
* @param cc
* @return
*/
private boolean lostGroundDescend(final Player player, final PlayerLocation from, final Location loc, final PlayerLocation to, final double hDistance, final double yDistance, final boolean sprinting, final MovingData data, final MovingConfig cc) {
private boolean lostGroundDescend(final Player player, final PlayerLocation from, final PlayerLocation to, final double hDistance, final double yDistance, final boolean sprinting, final MovingData data, final MovingConfig cc) {
// TODO: re-organize for faster exclusions (hDistance, yDistance).
// TODO: more strict conditions

View File

@ -20,6 +20,18 @@ public class SimpleAxisVelocity {
private final List<SimpleEntry> queued = new LinkedList<SimpleEntry>();
/**
* Add to the front of the queue.
* @param entry
*/
public void addToFront(SimpleEntry entry) {
queued.add(0, entry);
}
/**
* Add to the end of the queue.
* @param entry
*/
public void add(SimpleEntry entry) {
queued.add(entry);
}

View File

@ -481,7 +481,19 @@ public class TrigUtil {
}
/**
* Test if both locations have the exact same coordinates. Does not check yaw/pitch.
* Compare position and looking direction.
* @param loc1
* @param loc2
* @return Returns false if either is null.
*/
public static boolean isSamePosAndLook(final Location loc1, final Location loc2) {
return isSamePos(loc1, loc2) && loc1.getPitch() == loc2.getPitch() && loc1.getYaw() == loc2.getYaw();
}
/**
* Test if both locations have the exact same coordinates. Does not check
* yaw/pitch.
*
* @param loc1
* @param loc2
* @return Returns false if either is null.