use of fr.neatmonster.nocheatplus.utilities.location.PlayerLocation in project NoCheatPlus by NoCheatPlus.
the class MovingListener method checkPlayerMove.
/**
* @param player
* @param from
* @param to
* @param multiMoveCount
* 0: An ordinary move, not split. 1/2: first/second of a split
* move.
* @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 int multiMoveCount, final PlayerMoveInfo moveInfo, final boolean debug, final MovingData data, final MovingConfig cc, final IPlayerData pData, final PlayerMoveEvent event) {
Location newTo = null;
// TODO: Order this to above "early return"?
// Set up data / caching.
// TODO: Data resetting above ?
data.resetTeleported();
// Debug.
if (debug) {
outputMoveDebug(player, moveInfo.from, moveInfo.to, Math.max(cc.noFallyOnGround, cc.yOnGround), mcAccess.getHandle());
}
// Check for illegal move and bounding box etc.
if ((moveInfo.from.hasIllegalCoords() || moveInfo.to.hasIllegalCoords()) || !cc.ignoreStance && (moveInfo.from.hasIllegalStance() || moveInfo.to.hasIllegalStance())) {
MovingUtil.handleIllegalMove(event, player, data, cc);
return true;
}
// TODO: Could switch to UUID here (needs more changes).
final String playerName = player.getName();
// Check for location consistency.
if (cc.enforceLocation && playersEnforce.contains(playerName)) {
// NOTE: The setback should not be set before this, even if not yet set.
// Last to vs. from.
newTo = enforceLocation(player, from, data);
// TODO: Remove anyway ?
playersEnforce.remove(playerName);
}
final long time = System.currentTimeMillis();
if (player.isSprinting() || cc.assumeSprint) {
// TODO: Collect all these properties within a context object (abstraction + avoid re-fetching).
if (player.getFoodLevel() > 5 || player.getAllowFlight() || player.isFlying()) {
data.timeSprinting = time;
data.multSprinting = attributeAccess.getHandle().getSprintAttributeMultiplier(player);
if (data.multSprinting == Double.MAX_VALUE) {
data.multSprinting = 1.30000002;
} else if (cc.assumeSprint && data.multSprinting == 1.0) {
// Server side can be inconsistent, so the multiplier might be plain wrong (1.0).
// TODO: Could be more/less than actual, but "infinite" latency would not work either.
data.multSprinting = 1.30000002;
}
} else if (time < data.timeSprinting) {
data.timeSprinting = 0;
} else {
// keep sprinting time.
}
} else if (time < data.timeSprinting) {
data.timeSprinting = 0;
}
// Prepare locations for use.
// TODO: Block flags might not be needed if neither sf nor passable get checked.
final PlayerLocation pFrom, pTo;
pFrom = moveInfo.from;
pTo = moveInfo.to;
// HOT FIX - for VehicleLeaveEvent missing.
if (data.wasInVehicle) {
vehicleChecks.onVehicleLeaveMiss(player, data, cc, pData);
}
// Set some data for this move.
final PlayerMoveData thisMove = data.playerMoves.getCurrentMove();
thisMove.set(pFrom, pTo);
if (multiMoveCount > 0) {
thisMove.multiMoveCount = multiMoveCount;
}
final PlayerMoveData lastMove = data.playerMoves.getFirstPastMove();
// Potion effect "Jump".
/*
* TODO: Jump amplifier should be set in PlayerMoveData, and/or only get
* updated for lift off (?).
*/
final double jumpAmplifier = aux.getJumpAmplifier(player);
if (jumpAmplifier > data.jumpAmplifier) {
data.jumpAmplifier = jumpAmplifier;
}
// TODO: same for speed (once medium is introduced).
// Velocity tick (decrease + invalidation).
// TODO: Rework to generic (?) queued velocity entries: activation + invalidation
final int tick = TickTask.getTick();
data.velocityTick(tick - cc.velocityActivationTicks);
// Check which fly check to use.
final boolean checkCf;
final boolean checkSf;
if (MovingUtil.shouldCheckSurvivalFly(player, pFrom, data, cc, pData)) {
checkCf = false;
checkSf = true;
data.adjustWalkSpeed(player.getWalkSpeed(), tick, cc.speedGrace);
} else if (pData.isDebugActive(CheckType.MOVING_CREATIVEFLY)) {
checkCf = true;
checkSf = false;
prepareCreativeFlyCheck(player, from, to, moveInfo, thisMove, multiMoveCount, tick, data, cc);
} else {
checkCf = checkSf = false;
// (thisMove.flyCheck stays null.)
}
// Pre-check checks (hum), either for cf or for sf.
boolean checkNf = true;
BounceType verticalBounce = BounceType.NO_BOUNCE;
// TODO: More adaptive margin / method (bounding boxes).
final boolean useBlockChangeTracker;
final double previousSetBackY;
final boolean checkPassable = pData.isCheckActive(CheckType.MOVING_PASSABLE, player);
if (checkSf || checkCf) {
previousSetBackY = data.hasSetBack() ? data.getSetBackY() : Double.NEGATIVE_INFINITY;
// Ensure we have a set back set.
MovingUtil.checkSetBack(player, pFrom, data, pData, this);
// Check for special cross world teleportation issues with the end.
if (data.crossWorldFrom != null) {
if (// Safety check.
!TrigUtil.isSamePosAndLook(pFrom, pTo) && TrigUtil.isSamePosAndLook(pTo, data.crossWorldFrom)) {
// Assume to (and possibly the player location) to be set to the location the player teleported from within the other world.
// (OK, cross-world)
newTo = data.getSetBack(from);
checkNf = false;
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().warning(Streams.STATUS, CheckUtils.getLogMessagePrefix(player, CheckType.MOVING) + " Player move end point seems to be set wrongly.");
}
// Always reset.
data.crossWorldFrom = null;
}
// Extreme move check (sf or cf is precondition, should have their own config/actions later).
if (newTo == null && ((Math.abs(thisMove.yDistance) > Magic.EXTREME_MOVE_DIST_VERTICAL) || thisMove.hDistance > Magic.EXTREME_MOVE_DIST_HORIZONTAL)) {
// Test for friction and velocity.
newTo = checkExtremeMove(player, pFrom, pTo, data, cc);
if (newTo != null) {
thisMove.flyCheck = checkSf ? CheckType.MOVING_SURVIVALFLY : CheckType.MOVING_CREATIVEFLY;
}
}
useBlockChangeTracker = newTo == null && cc.trackBlockMove && (checkPassable || checkSf || checkCf) && blockChangeTracker.hasActivityShuffled(from.getWorld().getUID(), pFrom, pTo, 1.5625);
// Detect bounce type / use prepared bounce.
if (newTo == null) {
// TODO: With past states: What does jump effects do here?
if (thisMove.yDistance < 0.0) {
// TODO: Check if really leads to calling the method for pistons (checkBounceEnvelope vs. push).
if (!survivalFly.isReallySneaking(player) && checkBounceEnvelope(player, pFrom, pTo, data, cc, pData)) {
// Classic static bounce.
if ((BlockProperties.getBlockFlags(pTo.getTypeIdBelow()) & BlockProperties.F_BOUNCE25) != 0L) {
/*
* TODO: May need to adapt within this method, if
* "push up" happened and the trigger had been
* ordinary.
*/
verticalBounce = BounceType.STATIC;
// Skip NoFall.
checkNf = false;
}
if (verticalBounce == BounceType.NO_BOUNCE && useBlockChangeTracker) {
if (checkPastStateBounceDescend(player, pFrom, pTo, thisMove, lastMove, tick, data, cc) != BounceType.NO_BOUNCE) {
// Not set verticalBounce, as this is ascending and it's already force used.
// Skip NoFall.
checkNf = false;
}
}
}
} else {
if (// Prepared bounce support.
data.verticalBounce != null && onPreparedBounceSupport(player, from, to, thisMove, lastMove, tick, data) || // Past state bounce (includes prepending velocity / special calls).
useBlockChangeTracker && // 0-dist moves count in: && thisMove.yDistance >= 0.415
thisMove.yDistance <= // TODO: MAGIC
1.515) {
verticalBounce = checkPastStateBounceAscend(player, pFrom, pTo, thisMove, lastMove, tick, debug, data, cc);
if (verticalBounce != BounceType.NO_BOUNCE) {
checkNf = false;
}
}
}
}
} else {
// TODO: Might still allow block change tracker with only passable enabled.
useBlockChangeTracker = false;
previousSetBackY = Double.NEGATIVE_INFINITY;
}
// Check passable first to prevent set back override.
// TODO: Redesign to set set backs later (queue + invalidate).
// If to skip nofall check (mainly on violation of other checks).
boolean mightSkipNoFall = false;
if (newTo == null && checkPassable && player.getGameMode() != BridgeMisc.GAME_MODE_SPECTATOR) {
// Passable is checked first to get the original set back locations from the other checks, if needed.
newTo = passable.check(player, pFrom, pTo, data, cc, pData, tick, useBlockChangeTracker);
if (newTo != null) {
// Check if to skip the nofall check.
mightSkipNoFall = true;
}
}
// Flying checks.
if (checkSf) {
// SurvivalFly
// Prepare from, to, thisMove for full checking.
// TODO: Could further differentiate if really needed to (newTo / NoFall).
MovingUtil.prepareFullCheck(pFrom, pTo, thisMove, Math.max(cc.noFallyOnGround, cc.yOnGround));
// Hack: Add velocity for transitions between creativefly and survivalfly.
if (lastMove.toIsValid && lastMove.flyCheck == CheckType.MOVING_CREATIVEFLY) {
workaroundFlyNoFlyTransition(player, tick, debug, data);
}
// Actual check.
if (newTo == null) {
// Only check if passable has not already set back.
thisMove.flyCheck = CheckType.MOVING_SURVIVALFLY;
newTo = survivalFly.check(player, pFrom, pTo, multiMoveCount, data, cc, pData, tick, time, useBlockChangeTracker);
}
// Only check NoFall, if not already vetoed.
if (checkNf) {
checkNf = noFall.isEnabled(player, pData);
}
if (newTo == null) {
// TODO: Could reset for from-on-ground as well, for not too big moves.
if (cc.sfHoverCheck && !(lastMove.toIsValid && lastMove.to.extraPropertiesValid && lastMove.to.onGroundOrResetCond) && !pTo.isOnGround()) {
// Start counting ticks.
hoverTicks.add(playerName);
data.sfHoverTicks = 0;
} else {
data.sfHoverTicks = -1;
}
// NoFall.
if (checkNf) {
noFall.check(player, pFrom, pTo, previousSetBackY, data, cc, pData);
}
} else {
if (checkNf && cc.sfSetBackPolicyFallDamage) {
if (!noFall.willDealFallDamage(player, from.getY(), previousSetBackY, data)) {
// TODO: Consider making this / damage amount configurable.
mightSkipNoFall = true;
} else if (mightSkipNoFall) {
// Check if to really skip.
if (!pFrom.isOnGround() && !pFrom.isResetCond()) {
mightSkipNoFall = false;
}
}
if (!mightSkipNoFall && (!pTo.isResetCond() || !pFrom.isResetCond())) {
// (Don't deal damage where no fall damage is possible.)
noFall.checkDamage(player, Math.min(from.getY(), to.getY()), data, pData);
}
}
}
} else if (checkCf) {
// CreativeFly
if (newTo == null) {
thisMove.flyCheck = CheckType.MOVING_CREATIVEFLY;
newTo = creativeFly.check(player, pFrom, pTo, data, cc, pData, time, tick, useBlockChangeTracker);
}
data.sfHoverTicks = -1;
data.sfLowJump = false;
} else {
// No fly checking :(.
data.clearFlyData();
}
// Morepackets.
if (pData.isCheckActive(CheckType.MOVING_MOREPACKETS, player) && (newTo == null || data.isMorePacketsSetBackOldest())) {
/* (Always check morepackets, if there is a chance that setting/overriding newTo is appropriate,
to avoid packet speeding using micro-violations.) */
final Location mpNewTo = morePackets.check(player, pFrom, pTo, newTo == null, data, cc, pData);
if (mpNewTo != null) {
// Only override set back, if the morepackets set back location is older/-est.
if (newTo != null && debug) {
debug(player, "Override set back by the older morepackets set back.");
}
newTo = mpNewTo;
}
} else {
// Otherwise we need to clear their data.
data.clearPlayerMorePacketsData();
}
// Reset jump amplifier if needed.
if ((checkSf || checkCf) && jumpAmplifier != data.jumpAmplifier) {
// TODO: General cool-down for latency?
if (thisMove.touchedGround || !checkSf && (pFrom.isOnGround() || pTo.isOnGround())) {
// (No need to check from/to for onGround, if SurvivalFly is to be checked.)
data.jumpAmplifier = jumpAmplifier;
}
}
// Update BlockChangeTracker
if (useBlockChangeTracker && data.blockChangeRef.firstSpanEntry != null) {
if (debug) {
debug(player, "BlockChangeReference: " + data.blockChangeRef.firstSpanEntry.tick + " .. " + data.blockChangeRef.lastSpanEntry.tick + " / " + tick);
}
data.blockChangeRef.updateFinal(pTo);
}
if (newTo == null) {
// Allowed move.
if (data.hasTeleported()) {
data.resetTeleported();
if (debug) {
debug(player, "Ignore hook-induced set-back: actions not set to cancel.");
}
}
// Bounce effects.
if (verticalBounce != BounceType.NO_BOUNCE) {
processBounce(player, pFrom.getY(), pTo.getY(), verticalBounce, tick, debug, data, cc, pData);
}
// Finished move processing.
if (processingEvents.containsKey(playerName)) {
// Normal processing.
// TODO: More simple: UUID keys or a data flag instead?
data.playerMoves.finishCurrentMove();
} else {
// Teleport during violation processing, just invalidate thisMove.
thisMove.invalidate();
}
// Increase time since set back.
data.timeSinceSetBack++;
return false;
} else {
if (data.hasTeleported()) {
if (debug) {
debug(player, "The set back has been overridden from (" + newTo + ") to: " + data.getTeleported());
}
newTo = data.getTeleported();
}
if (debug) {
// TODO: Remove, if not relevant (doesn't look like it was :p).
if (verticalBounce != BounceType.NO_BOUNCE) {
debug(player, "Bounce effect not processed: " + verticalBounce);
}
if (data.verticalBounce != null) {
debug(player, "Bounce effect not used: " + data.verticalBounce);
}
}
// Set back handling.
prepareSetBack(player, event, newTo, data, cc, pData);
// Prevent freezing (e.g. ascending with gliding set in water, but moving normally).
if ((thisMove.flyCheck == CheckType.MOVING_SURVIVALFLY || thisMove.flyCheck == CheckType.MOVING_CREATIVEFLY && pFrom.isInLiquid()) && Bridge1_9.isGlidingWithElytra(player)) {
stopGliding(player);
}
return true;
}
}
use of fr.neatmonster.nocheatplus.utilities.location.PlayerLocation in project NoCheatPlus by NoCheatPlus.
the class SurvivalFly method handleHoverViolation.
/**
* Hover violations have to be handled in this check, because they are handled as SurvivalFly violations (needs executeActions).
* @param player
* @param loc
* @param blockCache
* @param cc
* @param data
*/
public final void handleHoverViolation(final Player player, final PlayerLocation loc, final MovingConfig cc, final MovingData data) {
data.survivalFlyVL += cc.sfHoverViolation;
// TODO: Extra options for set back / kick, like vl?
data.sfVLTime = data.getPlayerMoveCount();
data.sfVLInAir = true;
final ViolationData vd = new ViolationData(this, player, data.survivalFlyVL, cc.sfHoverViolation, cc.survivalFlyActions);
if (vd.needsParameters()) {
vd.setParameter(ParameterName.LOCATION_FROM, String.format(Locale.US, "%.2f, %.2f, %.2f", loc.getX(), loc.getY(), loc.getZ()));
vd.setParameter(ParameterName.LOCATION_TO, "(HOVER)");
vd.setParameter(ParameterName.DISTANCE, "0.0(HOVER)");
vd.setParameter(ParameterName.TAGS, "hover");
}
if (executeActions(vd).willCancel()) {
// Set back or kick.
final Location newTo = MovingUtil.getApplicableSetBackLocation(player, loc.getYaw(), loc.getPitch(), loc, data, cc);
if (newTo != null) {
data.prepareSetBack(newTo);
player.teleport(newTo, BridgeMisc.TELEPORT_CAUSE_CORRECTION_OF_POSITION);
} else {
// Solve by extra actions ? Special case (probably never happens)?
player.kickPlayer("Hovering?");
}
} else {
// Ignore.
}
}
use of fr.neatmonster.nocheatplus.utilities.location.PlayerLocation in project NoCheatPlus by NoCheatPlus.
the class MovingUtil method handleIllegalMove.
/**
* Handle an illegal move by a player, attempt to restore a valid location.
* <br>
* NOTE: event.setTo is used to not leave a gap.
*
* @param event
* @param player
* @param data
* @param cc
*/
public static void handleIllegalMove(final PlayerMoveEvent event, final Player player, final MovingData data, final MovingConfig cc) {
// This might get extended to a check-like thing.
boolean restored = false;
final PlayerLocation pLoc = new PlayerLocation(NCPAPIProvider.getNoCheatPlusAPI().getGenericInstanceHandle(MCAccess.class), null);
// (Mind that we don't set the block cache here).
final Location loc = player.getLocation();
if (!restored && data.hasSetBack()) {
/*
* TODO: Harmonize with MovingUtil.getApplicableSetBackLocation
* (somehow include the desired set back type / loc / context).
*/
// TODO
final Location setBack = data.getSetBack(loc);
pLoc.set(setBack, player);
if (!pLoc.hasIllegalCoords() && (cc.ignoreStance || !pLoc.hasIllegalStance())) {
event.setFrom(setBack);
event.setTo(setBack);
restored = true;
} else {
data.resetSetBack();
}
}
if (!restored) {
pLoc.set(loc, player);
if (!pLoc.hasIllegalCoords() && (cc.ignoreStance || !pLoc.hasIllegalStance())) {
event.setFrom(loc);
event.setTo(loc);
restored = true;
}
}
pLoc.cleanup();
if (!restored) {
// TODO: reset the bounding box of the player ?
if (cc.tempKickIllegal) {
NCPAPIProvider.getNoCheatPlusAPI().denyLogin(player.getName(), 24L * 60L * 60L * 1000L);
StaticLog.logSevere("[NCP] could not restore location for " + player.getName() + ", kicking them and deny login for 24 hours");
} else {
StaticLog.logSevere("[NCP] could not restore location for " + player.getName() + ", kicking them.");
}
CheckUtils.kickIllegalMove(player, cc);
}
}
use of fr.neatmonster.nocheatplus.utilities.location.PlayerLocation in project NoCheatPlus by NoCheatPlus.
the class SurvivalFly method check.
/**
* @param player
* @param from
* @param to
* @param multiMoveCount
* =: Ordinary, 1/2: first/second of a split move.
* @param data
* @param cc
* @param tick
* @param now
* @param useBlockChangeTracker
* @return
*/
public Location check(final Player player, final PlayerLocation from, final PlayerLocation to, final int multiMoveCount, final MovingData data, final MovingConfig cc, final IPlayerData pData, final int tick, final long now, final boolean useBlockChangeTracker) {
tags.clear();
final boolean debug = pData.isDebugActive(type);
if (debug) {
justUsedWorkarounds.clear();
data.ws.setJustUsedIds(justUsedWorkarounds);
}
final PlayerMoveData thisMove = data.playerMoves.getCurrentMove();
final PlayerMoveData lastMove = data.playerMoves.getFirstPastMove();
final boolean isSamePos = from.isSamePos(to);
// Calculate some distances.
final double xDistance, yDistance, zDistance, hDistance;
final boolean hasHdist;
if (isSamePos) {
// TODO: Could run a completely different check here (roughly none :p).
xDistance = yDistance = zDistance = hDistance = 0.0;
hasHdist = false;
} else {
xDistance = to.getX() - from.getX();
yDistance = thisMove.yDistance;
zDistance = to.getZ() - from.getZ();
if (xDistance == 0.0 && zDistance == 0.0) {
hDistance = 0.0;
hasHdist = false;
} else {
hasHdist = true;
hDistance = thisMove.hDistance;
}
}
// Recover from data removal (somewhat random insertion point).
if (data.liftOffEnvelope == LiftOffEnvelope.UNKNOWN) {
data.adjustMediumProperties(from);
}
// Set some flags.
final boolean fromOnGround = thisMove.from.onGround;
// TODO: Work in the past ground stuff differently (thisMove, touchedGround?, from/to ...)
final boolean toOnGround = thisMove.to.onGround || useBlockChangeTracker && toOnGroundPastStates(from, to, thisMove, tick, data, cc);
final boolean resetTo = toOnGround || to.isResetCond();
// Determine if the player is actually sprinting.
final boolean sprinting;
if (data.lostSprintCount > 0) {
// NOTE: This could extend the "sprinting grace" period, theoretically, until on ground.
if (resetTo && (fromOnGround || from.isResetCond()) || hDistance <= Magic.WALK_SPEED) {
// Invalidate.
data.lostSprintCount = 0;
tags.add("invalidate_lostsprint");
if (now <= data.timeSprinting + cc.sprintingGrace) {
sprinting = true;
} else {
sprinting = false;
}
} else {
tags.add("lostsprint");
sprinting = true;
if (data.lostSprintCount < 3 && toOnGround || to.isResetCond()) {
data.lostSprintCount = 0;
} else {
data.lostSprintCount--;
}
}
} else if (now <= data.timeSprinting + cc.sprintingGrace) {
// Within grace period for hunger level being too low for sprinting on server side (latency).
if (now != data.timeSprinting) {
tags.add("sprintgrace");
}
sprinting = true;
} else {
sprinting = false;
}
// Use the player-specific walk speed.
// TODO: Might get from listener.
// TODO: Use in lostground?
thisMove.walkSpeed = Magic.WALK_SPEED * ((double) data.walkSpeed / Magic.DEFAULT_WALKSPEED);
setNextFriction(thisMove, data, cc);
// ///////////////////////////////
// Mixed checks (lost ground).
// ///////////////////////////////
final boolean resetFrom;
if (fromOnGround || from.isResetCond()) {
resetFrom = true;
} else // TODO: Extra workarounds for toOnGround (step-up is a case with to on ground)?
if (isSamePos) {
// TODO: This isn't correct, needs redesign.
if (useBlockChangeTracker && from.isOnGroundOpportune(cc.yOnGround, 0L, blockChangeTracker, data.blockChangeRef, tick)) {
// TODO: Quick addition. Reconsider entry points etc.
resetFrom = true;
tags.add("pastground_from");
} else if (lastMove.toIsValid) {
// Note that to is not on ground either.
resetFrom = LostGround.lostGroundStill(player, from, to, hDistance, yDistance, sprinting, lastMove, data, cc, tags);
} else {
resetFrom = false;
}
} else {
// "Lost ground" workaround.
// TODO: More refined conditions possible ?
// TODO: Consider if (!resetTo) ?
// Check lost-ground workarounds.
resetFrom = LostGround.lostGround(player, from, to, hDistance, yDistance, sprinting, lastMove, data, cc, useBlockChangeTracker ? blockChangeTracker : null, tags);
// Note: if not setting resetFrom, other places have to check assumeGround...
}
if (thisMove.touchedGround) {
if (!thisMove.from.onGround && !thisMove.to.onGround) {
// Lost ground workaround has just been applied, check resetting of the dirty flag.
// TODO: Always/never reset with any ground touched?
data.resetVelocityJumpPhase(tags);
} else if (multiMoveCount == 0 && thisMove.from.onGround && !lastMove.touchedGround && TrigUtil.isSamePosAndLook(thisMove.from, lastMove.to)) {
// Ground somehow appeared out of thin air (block place).
data.setSetBack(from);
if (debug) {
debug(player, "Adjust set back on move: from is now on ground.");
}
}
}
// Renew the "dirty"-flag (in-air phase affected by velocity).
if (data.isVelocityJumpPhase() || data.resetVelocityJumpPhase(tags)) {
// (Reset is done after checks run.)
tags.add("dirty");
}
// Check if head is obstructed.
// if (!resetFrom || !resetTo) {
thisMove.headObstructed = (yDistance > 0.0 ? from.isHeadObstructed(yDistance) : from.isHeadObstructed());
// TODO: Consider setting on ground_height always?
if ((from.getBlockFlags() & BlockProperties.F_ALLOW_LOWJUMP) != 0) {
// TODO: Specialize - test for foot region?
data.sfNoLowJump = true;
}
// ////////////////////
// Horizontal move.
// ////////////////////
// TODO: Account for lift-off medium / if in air [i.e. account for medium + friction]?
// Alter some data / flags.
// TODO: Design to do the changing at the bottom? [if change: check limits in bunnyHop(...)]
data.bunnyhopDelay--;
// Set flag for swimming with the flowing direction of liquid.
thisMove.downStream = hDistance > thisMove.walkSpeed * Magic.modSwim && thisMove.from.inLiquid && from.isDownStream(xDistance, zDistance);
// TODO: Re-model ice stuff and other (e.g. general thing: ground-modifier + reset conditions).
if (thisMove.from.onIce || thisMove.to.onIce) {
// TODO: 1. Test if this can simply be removed. 2. Ensure data.sfOnIce resets with a violation.
data.sfOnIce = 20;
} else if (data.sfOnIce > 0) {
// TODO: Here some friction might apply, could become a general thing with bunny and other.
// TODO: Other reset conditions.
data.sfOnIce--;
}
/*
* TODO: if (Bridge1_9.isGlidingWithElytra(player)) { // Force stop
* gliding?
*/
// TODO: Remove these local variables ?
double hAllowedDistance = 0.0, hDistanceAboveLimit = 0.0, hFreedom = 0.0;
if (hasHdist) {
// Check allowed vs. taken horizontal distance.
// Get the allowed distance.
hAllowedDistance = setAllowedhDist(player, sprinting, thisMove, data, cc, pData, false);
// Judge if horizontal speed is above limit.
hDistanceAboveLimit = hDistance - hAllowedDistance;
// Velocity, buffers and after failure checks.
if (hDistanceAboveLimit > 0) {
// TODO: Move more of the workarounds (buffer, bunny, ...) into this method.
final double[] res = hDistAfterFailure(player, from, to, hAllowedDistance, hDistanceAboveLimit, sprinting, thisMove, lastMove, data, cc, pData, false);
hAllowedDistance = res[0];
hDistanceAboveLimit = res[1];
hFreedom = res[2];
} else {
data.clearActiveHorVel();
hFreedom = 0.0;
if (resetFrom && data.bunnyhopDelay <= 6) {
data.bunnyhopDelay = 0;
}
}
// hacc (if enabled, always update)
final double fcmhv = Math.max(1.0, Math.min(10.0, thisMove.hDistance / thisMove.hAllowedDistanceBase));
data.combinedMediumHCount++;
data.combinedMediumHValue += fcmhv;
// TODO: Balance, where to check / use (...).
if (data.combinedMediumHCount > 30) {
// TODO: Early trigger (> 0,1,2,5?), for way too high values. [in that case don't reset]
final double fcmh = data.combinedMediumHValue / (double) data.combinedMediumHCount;
final double limitFCMH;
// TODO: with buffer use, might want to skip.
if (data.liftOffEnvelope == LiftOffEnvelope.NORMAL) {
limitFCMH = 1.34;
} else if (data.liftOffEnvelope == LiftOffEnvelope.LIMIT_LIQUID || data.liftOffEnvelope == LiftOffEnvelope.LIMIT_NEAR_GROUND) {
// limitFCMH = 1.05; // Seems to work on 1.10
// 1.8.8 in-water moves with jumping near/on surface. 1.2 is max factor for one move (!).
limitFCMH = 1.1;
// TODO: Version+context dependent setting and/or confine by in-water moves, whatever.
} else {
limitFCMH = 1.0;
}
// TODO: Fly-NoFly + bunny-water transitions pose issues.
if (fcmh > limitFCMH && !data.isVelocityJumpPhase()) {
hDistanceAboveLimit = hDistance * (fcmh - limitFCMH);
tags.add("hacc");
// Reset for now.
data.combinedMediumHCount = 0;
data.combinedMediumHValue = 0.0;
} else {
// TODO: Other cases (1.0, between, ...)?
data.combinedMediumHCount = 1;
data.combinedMediumHValue = fcmhv;
}
}
// TODO: Complete re-modeling.
if (hDistanceAboveLimit <= 0D && hDistance > 0.1D && yDistance == 0D && !toOnGround && !fromOnGround && lastMove.toIsValid && lastMove.yDistance == 0D && BlockProperties.isLiquid(to.getTypeId()) && BlockProperties.isLiquid(from.getTypeId()) && !from.isHeadObstructed() && // TODO: Might decrease margin here.
!to.isHeadObstructed()) {
// TODO: Relative hdistance.
// TODO: Might check actual bounds (collidesBlock). Might implement + use BlockProperties.getCorrectedBounds or getSomeHeight.
hDistanceAboveLimit = Math.max(hDistanceAboveLimit, hDistance);
tags.add("waterwalk");
}
// Prevent players from sprinting if they're moving backwards (allow buffers to cover up !?).
if (sprinting && data.lostSprintCount == 0 && !cc.assumeSprint && hDistance > thisMove.walkSpeed && !data.hasActiveHorVel()) {
// TODO: speed effects ?
if (TrigUtil.isMovingBackwards(xDistance, zDistance, from.getYaw()) && !pData.hasPermission(Permissions.MOVING_SURVIVALFLY_SPRINTING, player)) {
// (Might have to account for speeding permissions.)
// TODO: hDistance is too harsh?
hDistanceAboveLimit = Math.max(hDistanceAboveLimit, hDistance);
// Might add it anyway.
tags.add("sprintback");
}
}
} else {
/*
* TODO: Consider to log and/or remember when this was last time
* cleared [add time distance to tags/log on violations].
*/
data.clearActiveHorVel();
thisMove.hAllowedDistanceBase = 0.0;
thisMove.hAllowedDistance = 0.0;
// TODO: Other properties should be set as well?
}
// ////////////////////////
// Vertical move.
// ////////////////////////
// Calculate the vertical speed limit based on the current jump phase.
double vAllowedDistance = 0, vDistanceAboveLimit = 0;
// Distinguish certain media.
if (yDistance >= 0.0 && yDistance <= cc.sfStepHeight && toOnGround && fromOnGround) {
// Wild-card allow step height from ground to ground.
// TODO: Which of (fromOnGround || data.noFallAssumeGround || lastMove.toIsValid && lastMove.yDistance < 0.0)?
vAllowedDistance = cc.sfStepHeight;
} else if (from.isInWeb()) {
// TODO: Further confine conditions.
final double[] res = vDistWeb(player, thisMove, toOnGround, hDistanceAboveLimit, now, data, cc);
vAllowedDistance = res[0];
vDistanceAboveLimit = res[1];
if (res[0] == Double.MIN_VALUE && res[1] == Double.MIN_VALUE) {
// Silent set back.
if (debug) {
tags.add("silentsbcobweb");
outputDebug(player, to, data, cc, hDistance, hAllowedDistance, hFreedom, yDistance, vAllowedDistance, fromOnGround, resetFrom, toOnGround, resetTo, thisMove);
data.ws.setJustUsedIds(null);
}
// (OK)
return data.getSetBack(to);
}
} else if (from.isOnClimbable()) {
// Ladder types.
vDistanceAboveLimit = vDistClimbable(player, from, to, fromOnGround, toOnGround, thisMove, lastMove, yDistance, data);
} else if (thisMove.from.inLiquid) {
// && (Math.abs(yDistance) > 0.2 || to.isInLiquid())) {
// Swimming...
final double[] res = vDistLiquid(from, to, toOnGround, yDistance, lastMove, data);
vAllowedDistance = res[0];
vDistanceAboveLimit = res[1];
if (vDistanceAboveLimit <= 0.0 && yDistance > 0.0 && Math.abs(yDistance) > Magic.swimBaseSpeedV()) {
data.setFrictionJumpPhase();
}
} else {
final double[] res = vDistAir(now, player, from, fromOnGround, resetFrom, to, toOnGround, resetTo, hDistanceAboveLimit, yDistance, multiMoveCount, lastMove, data, cc, pData);
vAllowedDistance = res[0];
vDistanceAboveLimit = res[1];
}
// Post-check recovery.
if (useBlockChangeTracker && vDistanceAboveLimit > 0.0) // Skip for now: && Math.abs(yDistance) <= 1.55
{
// TODO: Better place for checking for moved blocks [redesign for intermediate result objects?].
// Vertical push/pull.
double[] blockMoveResult = getVerticalBlockMoveResult(yDistance, from, to, tick, data);
if (blockMoveResult != null) {
vAllowedDistance = blockMoveResult[0];
vDistanceAboveLimit = blockMoveResult[1];
}
}
// Push/pull sideways.
// TODO: Slightly itchy: regard x and z separately (Better in another spot).
// TODO: on ground -> on ground improvements.
// Debug output.
final int tagsLength;
if (debug) {
outputDebug(player, to, data, cc, hDistance, hAllowedDistance, hFreedom, yDistance, vAllowedDistance, fromOnGround, resetFrom, toOnGround, resetTo, thisMove);
tagsLength = tags.size();
data.ws.setJustUsedIds(null);
} else {
// JIT vs. IDE.
tagsLength = 0;
}
// /////////////////////
// Handle violations.
// /////////////////////
final boolean inAir = Magic.inAir(thisMove);
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 (inAir) {
data.sfVLInAir = true;
}
if (vLoc != null) {
return vLoc;
}
} else {
// TODO: Switch to move count instead of time (!).
if (data.getPlayerMoveCount() - data.sfVLTime > cc.survivalFlyVLFreezeCount && (!cc.survivalFlyVLFreezeInAir || !inAir || // Favor bunny-hopping slightly: clean descend.
!data.sfVLInAir && data.liftOffEnvelope == LiftOffEnvelope.NORMAL && lastMove.toIsValid && lastMove.yDistance < -Magic.GRAVITY_MIN && thisMove.yDistance - lastMove.yDistance < -Magic.GRAVITY_MIN)) {
// Relax VL.
data.survivalFlyVL *= 0.95;
// Finally check horizontal buffer regain.
if (hDistanceAboveLimit < 0.0 && result <= 0.0 && !isSamePos && data.sfHorizontalBuffer < cc.hBufMax) {
// TODO: max min other conditions ?
hBufRegain(hDistance, Math.min(0.2, Math.abs(hDistanceAboveLimit)), data, cc);
}
}
}
// ////////////////////////////////////////////////////////////////////////////////////////////
// Set data for normal move or violation without cancel (cancel would have returned above).
// ////////////////////////////////////////////////////////////////////////////////////////////
// Check LiftOffEnvelope.
// TODO: Web before liquid? Climbable?
// TODO: isNextToGround(0.15, 0.4) allows a little much (yMargin), but reduces false positives.
// TODO: nextToGround: Shortcut with block-flags ?
final LiftOffEnvelope oldLiftOffEnvelope = data.liftOffEnvelope;
if (to.isInLiquid()) {
if (fromOnGround && !toOnGround && data.liftOffEnvelope == LiftOffEnvelope.NORMAL && data.sfJumpPhase <= 0 && !thisMove.from.inLiquid) {
// KEEP
} else if (to.isNextToGround(0.15, 0.4)) {
// Consent with ground.
data.liftOffEnvelope = LiftOffEnvelope.LIMIT_NEAR_GROUND;
} else {
// TODO: Distinguish strong limit from normal.
data.liftOffEnvelope = LiftOffEnvelope.LIMIT_LIQUID;
}
} else if (thisMove.to.inWeb) {
// TODO: Test.
data.liftOffEnvelope = LiftOffEnvelope.NO_JUMP;
} else if (resetTo) {
// TODO: This might allow jumping on vines etc., but should do for the moment.
data.liftOffEnvelope = LiftOffEnvelope.NORMAL;
} else if (thisMove.from.inLiquid) {
if (!resetTo && data.liftOffEnvelope == LiftOffEnvelope.NORMAL && data.sfJumpPhase <= 0) {
// KEEP
} else if (to.isNextToGround(0.15, 0.4)) {
// TODO: Problematic: y-distance slope can be low jump.
data.liftOffEnvelope = LiftOffEnvelope.LIMIT_NEAR_GROUND;
} else {
// TODO: Distinguish strong limit.
data.liftOffEnvelope = LiftOffEnvelope.LIMIT_LIQUID;
}
} else if (thisMove.from.inWeb) {
// TODO: Test.
data.liftOffEnvelope = LiftOffEnvelope.NO_JUMP;
} else if (resetFrom || thisMove.touchedGround) {
// TODO: Where exactly to put noFallAssumeGround ?
data.liftOffEnvelope = LiftOffEnvelope.NORMAL;
} else {
// Keep medium.
// TODO: Is above stairs ?
}
// Count how long one is moving inside of a medium.
if (oldLiftOffEnvelope != data.liftOffEnvelope) {
data.insideMediumCount = 0;
data.combinedMediumHCount = 0;
data.combinedMediumHValue = 0.0;
} else if (!resetFrom || !resetTo) {
data.insideMediumCount = 0;
} else {
data.insideMediumCount++;
}
// Apply reset conditions.
if (resetTo) {
// The player has moved onto ground.
if (toOnGround) {
// Reset bunny-hop-delay.
if (data.bunnyhopDelay > 0 && yDistance > 0.0 && to.getY() > data.getSetBackY() + 0.12 && !from.isResetCond() && !to.isResetCond()) {
data.bunnyhopDelay = 0;
tags.add("resetbunny");
}
}
// Reset data.
data.setSetBack(to);
data.sfJumpPhase = 0;
data.clearAccounting();
data.sfNoLowJump = false;
if (data.sfLowJump && resetFrom) {
// Prevent reset if coming from air (purpose of the flag).
data.sfLowJump = false;
}
if (hFreedom <= 0.0 && thisMove.verVelUsed == null) {
data.resetVelocityJumpPhase(tags);
}
} else if (resetFrom) {
// The player moved from ground.
data.setSetBack(from);
// This event is already in air.
data.sfJumpPhase = 1;
data.clearAccounting();
data.sfLowJump = false;
// not resetting nolowjump (?)...
// Don't reset velocity phase unless moving into resetcond.
// if (hFreedom <= 0.0 && data.verVelUsed == null && (!data.noFallAssumeGround || fromOnGround)) {
// data.resetVelocityJumpPhase(tags);
// }
} else {
data.sfJumpPhase++;
// TODO: Void-to-void: Rather handle unified somewhere else (!).
if (to.getY() < 0.0 && cc.sfSetBackPolicyVoid) {
data.setSetBack(to);
}
}
if (inAir) {
// Adjust in-air counters.
if (yDistance == 0.0) {
data.sfZeroVdistRepeat++;
} else {
data.sfZeroVdistRepeat = 0;
}
} else {
data.sfZeroVdistRepeat = 0;
data.ws.resetConditions(WRPT.G_RESET_NOTINAIR);
data.sfVLInAir = false;
}
// Horizontal velocity invalidation.
if (hDistance <= (cc.velocityStrictInvalidation ? thisMove.hAllowedDistanceBase : thisMove.hAllowedDistanceBase / 2.0)) {
// TODO: Should there be other side conditions?
// Invalidate used horizontal velocity.
// debug(player, "*** INVALIDATE ON SPEED");
data.clearActiveHorVel();
}
// TODO: Pull down tick / timing data (perhaps add an API object for millis + source + tick + sequence count (+ source of sequence count).
if (debug) {
// TODO: Only update, if velocity is queued at all.
data.getVerticalVelocityTracker().updateBlockedState(tick, // Assume blocked with being in web/water, despite not entirely correct.
thisMove.headObstructed || thisMove.from.resetCond, // (Similar here.)
thisMove.touchedGround || thisMove.to.resetCond);
// TODO: TEST: Check unused velocity here too. (Should have more efficient process, pre-conditions for checking.)
UnusedVelocity.checkUnusedVelocity(player, type, data, cc);
}
// Adjust data.
data.lastFrictionHorizontal = data.nextFrictionHorizontal;
data.lastFrictionVertical = data.nextFrictionVertical;
// Log tags added after violation handling.
if (debug && tags.size() > tagsLength) {
logPostViolationTags(player);
}
return null;
}
use of fr.neatmonster.nocheatplus.utilities.location.PlayerLocation in project NoCheatPlus by NoCheatPlus.
the class MovingListener method checkFallDamageEvent.
private void checkFallDamageEvent(final Player player, final EntityDamageEvent event) {
final IPlayerData pData = DataManager.getPlayerData(player);
final MovingData data = pData.getGenericInstance(MovingData.class);
if (player.isInsideVehicle()) {
// Ignore vehicles (noFallFallDistance will be inaccurate anyway).
data.clearNoFallData();
return;
}
final MovingConfig cc = pData.getGenericInstance(MovingConfig.class);
final PlayerMoveInfo moveInfo = aux.usePlayerMoveInfo();
final double yOnGround = Math.max(cc.noFallyOnGround, cc.yOnGround);
final Location loc = player.getLocation(useLoc);
moveInfo.set(player, loc, null, yOnGround);
final PlayerLocation pLoc = moveInfo.from;
pLoc.collectBlockFlags(yOnGround);
if (event.isCancelled() || !MovingUtil.shouldCheckSurvivalFly(player, pLoc, data, cc, pData) || !noFall.isEnabled(player, pData)) {
data.clearNoFallData();
useLoc.setWorld(null);
aux.returnPlayerMoveInfo(moveInfo);
return;
}
final boolean debug = pData.isDebugActive(CheckType.MOVING_NOFALL);
boolean allowReset = true;
float fallDistance = player.getFallDistance();
final float yDiff = (float) (data.noFallMaxY - loc.getY());
// Raw damage.
final double damage = BridgeHealth.getRawDamage(event);
// TODO: Account for modifiers.
if (debug) {
debug(player, "Damage(FALL/PRE): " + damage + " / mc=" + player.getFallDistance() + " nf=" + data.noFallFallDistance + " yDiff=" + yDiff);
}
// NoFall bypass checks.
if (!data.noFallSkipAirCheck) {
// Cheat: let Minecraft gather and deal fall damage.
/*
* TODO: data.noFallSkipAirCheck is used to skip checking in
* general, thus move into that block or not?
*/
// TODO: Could consider skipping accumulated fall distance for NoFall in general as well.
final float dataDist = Math.max(yDiff, data.noFallFallDistance);
final double dataDamage = NoFall.getDamage(dataDist);
if (damage > dataDamage + 0.5 || dataDamage <= 0.0) {
// TODO: Also relate past y-distance(s) to the fall distance (mc).
// Hot fix: allow fall damage in lava.
/*
* TODO: Correctly model the half fall distance per in-lava move
* and taking fall damage in lava. Should have a block flag for
* this.
*/
final PlayerMoveData firstPastMove = data.playerMoves.getFirstPastMove();
if (pLoc.isOnGround() && pLoc.isInLava() && firstPastMove.toIsValid && firstPastMove.yDistance < 0.0) {
/*
* 1. Strictly someone could attempt to accumulate fall
* damage by help of fast place and pickup lava. 2. There
* are other cases not ending up in lava, but having a
* reduced fall distance (then bigger than nofall data).
*/
if (debug) {
debug(player, "NoFall/Damage: allow fall damage in lava (hotfix).");
}
} else if (noFallVL(player, "fakefall", data, cc)) {
// NOTE: Double violations are possible with the in-air check below.
// TODO: Differing sub checks, once cancel action...
player.setFallDistance(dataDist);
if (dataDamage <= 0.0) {
// Cancel the event.
event.setCancelled(true);
useLoc.setWorld(null);
aux.returnPlayerMoveInfo(moveInfo);
return;
} else {
// Adjust and continue.
if (debug) {
debug(player, "NoFall/Damage: override player fall distance and damage (" + fallDistance + " -> " + dataDist + ").");
}
fallDistance = dataDist;
BridgeHealth.setRawDamage(event, dataDamage);
}
}
}
// Cheat: set ground to true in-air.
// Be sure not to lose that block.
// TODO: What is this and why is it right here?
data.noFallFallDistance += 1.0;
// TODO: Account for liquid too?
if (!pLoc.isOnGround(1.0, 0.3, 0.1) && !pLoc.isResetCond() && !pLoc.isAboveLadder() && !pLoc.isAboveStairs()) {
// Likely: force damage in mid-air by setting on-ground to true.
if (noFallVL(player, "fakeground", data, cc) && data.hasSetBack()) {
// Cancel the event and restore fall distance.
// NoFall data will not be reset
allowReset = false;
}
} else {
// Legitimate damage: clear accounting data.
data.vDistAcc.clear();
// TODO: Why only reset in case of !data.noFallSkipAirCheck?
// TODO: Also reset other properties.
// TODO: Also reset in other cases (moved too quickly)?
}
}
aux.returnPlayerMoveInfo(moveInfo);
// Fall-back check (skip with jump amplifier).
final double maxD = data.jumpAmplifier > 0.0 ? NoFall.getDamage((float) NoFall.getApplicableFallHeight(player, loc.getY(), data)) : NoFall.getDamage(Math.max(yDiff, Math.max(data.noFallFallDistance, fallDistance))) + (allowReset ? 0.0 : Magic.FALL_DAMAGE_DIST);
if (maxD > damage) {
// TODO: respect dealDamage ?
BridgeHealth.setRawDamage(event, maxD);
if (debug) {
debug(player, "Adjust fall damage to: " + maxD);
}
}
if (allowReset) {
// Normal fall damage, reset data.
data.clearNoFallData();
if (debug) {
debug(player, "Reset NoFall data on fall damage.");
}
} else {
// (Do not cancel the event, otherwise: "moved too quickly exploit".)
if (cc.noFallViolationReset) {
data.clearNoFallData();
}
// Add player to hover checks.
if (cc.sfHoverCheck && data.sfHoverTicks < 0) {
data.sfHoverTicks = 0;
hoverTicks.add(player.getName());
}
}
// Entity fall-distance should be reset elsewhere.
// Cleanup.
useLoc.setWorld(null);
}
Aggregations