[BLEEDING][BREAKING] Next step on past bounce with pistons.

Steps done:
* Add more velocity with less preconditions.
* Handle push with the player being just above the block where a slime
block is pushed to.
* Exception for vdistrel.
* Breaking:Move verVelUsed from MovingData to PlayerMoveData.

Gameplay issues remaining:
* Still too often fall damage is dealt.
* Friction envelope gets hidden with past-ground being set too often
(vdistsb).
* Potential for more edge cases.

Missing abuse prevention:
* Reinstate invalidation of past entries (currently turned off to
progress at all, will need another iteration).
* More confined preconditions.
* More/better invalidation conditions for velocity set for bounce
effects.
This commit is contained in:
asofold 2016-12-17 15:07:23 +01:00
parent cf3ea4a1e2
commit c9a744a7d3
5 changed files with 88 additions and 78 deletions

View File

@ -167,8 +167,6 @@ public class MovingData extends ACheckData {
/** Last time the player was actually sprinting. */
public long timeSprinting = 0;
public double multSprinting = 1.30000002; // Multiplier at the last time sprinting.
/** Just used velocity, during processing of moving checks. */
public SimpleEntry verVelUsed = null;
/** Compatibility entry for bouncing of slime blocks and the like. */
public SimpleEntry verticalBounce = null;
/** Last used block change id (BlockChangeTracker). */
@ -401,7 +399,6 @@ public class MovingData extends ACheckData {
insideMediumCount = 0;
vehicleConsistency = MoveConsistency.INCONSISTENT;
lastFrictionHorizontal = lastFrictionVertical = 0.0;
verVelUsed = null;
verticalBounce = null;
blockChangeRef.valid = false;
}
@ -940,9 +937,6 @@ public class MovingData extends ACheckData {
if (!sfDirty && (horVel.hasActive() || horVel.hasQueued())) {
sfDirty = true;
}
// Reset the "just used" velocity.
verVelUsed = null;
}
/**
@ -994,7 +988,7 @@ public class MovingData extends ACheckData {
public SimpleEntry useVerticalVelocity(final double amount) {
final SimpleEntry available = verVel.use(amount, TOL_VVEL);
if (available != null) {
verVelUsed = available;
playerMoves.getCurrentMove().verVelUsed = available;
sfDirty = true;
// TODO: Consider sfNoLowJump = true;
}
@ -1009,6 +1003,7 @@ public class MovingData extends ACheckData {
* @return
*/
public SimpleEntry getOrUseVerticalVelocity(final double amount) {
final SimpleEntry verVelUsed = playerMoves.getCurrentMove().verVelUsed;
if (verVelUsed != null) {
if (verVel.matchesEntry(verVelUsed, amount, TOL_VVEL)) {
return verVelUsed;

View File

@ -149,7 +149,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
*
*/
private static final long FLAGS_VELOCITY_BOUNCE_BLOCK = VelocityFlags.ORIGIN_BLOCK_BOUNCE;
private static final long FLAGS_VELOCITY_BOUNCE_BLOCK_MOVE_ASCEND = FLAGS_VELOCITY_BOUNCE_BLOCK
| VelocityFlags.SPLIT_ABOVE_0_42 | VelocityFlags.SPLIT_RETAIN_ACTCOUNT | VelocityFlags.ORIGIN_BLOCK_MOVE;
@ -912,9 +912,9 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
final PlayerMoveData thisMove, final PlayerMoveData lastMove, final int tick,
final MovingData data, final MovingConfig cc) {
// TODO: Find more preconditions.
// TODO: Might later need to override/adapt just the bounce effect set by the ordinary method.
final UUID worldId = from.getWorld().getUID();
// Prepare (normal/extra) bounce.
// TODO: Might later need to override/adapt just the bounce effect set by the ordinary method.
// Typical: a slime block has been there.
final BlockChangeEntry entryBelowAny = blockChangeTracker.getBlockChangeEntryMatchFlags(
data.blockChangeRef, tick, worldId, to.getBlockX(), to.getBlockY() - 1, to.getBlockZ(),
@ -923,7 +923,6 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// TODO: Check preconditions for bouncing here at all (!).
// Check if the/a block below the feet of the player got pushed into the feet of the player.
// TODO: Not sure if this can/should be done on ascending.
final BlockChangeEntry entryBelowY_POS = entryBelowAny.direction == Direction.Y_POS ? entryBelowAny
: blockChangeTracker.getBlockChangeEntryMatchFlags(data.blockChangeRef, tick, worldId,
to.getBlockX(), to.getBlockY() - 1, to.getBlockZ(), Direction.Y_POS,
@ -938,8 +937,6 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
return BounceType.STATIC_PAST;
}
}
// TODO: ADDITIONAL: A slime block has been pushed up [a) block below counts ? b) into the feet of the player].
/*
* TODO: Can't update span here. If at all, it can be added as side
* condition for using the bounce effect. Probably not worth it.
@ -951,63 +948,65 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
final Player player, final PlayerLocation from, final PlayerLocation to,
final PlayerMoveData thisMove, final PlayerMoveData lastMove, final int tick,
final MovingData data, final MovingConfig cc) {
// TODO: find more preconditions.
// TODO: More preconditions.
// TODO: Nail down to more precise side conditions for larger jumps, if possible.
final UUID worldId = from.getWorld().getUID();
// Possibly a "lost use of slime".
// TODO: Might need to cover push up, after ordinary slime bounce.
// TODO: Cover push by slime block (center/feet on block).
// TODO: Might need to cover push by slime block (center/feet off block).
// TODO: Low fall distance cases and where no slime block was underneath at descend have to be included here.
// TODO: Note that onPreparedBounceSupport etc. has to be called in here, if needed.
// TODO: Work around 0-dist?
// TODO: set data.verticalBounce and call data.useVerticalBounce right away (!) -> fall damage !?
// TODO: typically up to 1.5 above max level of pushed block ! (typically 2.0 total with 0.0 between).
/*
* TODO: Other concepts? a) maxCoordinate for SimpleEntry? (alters
* method calls to SimpleAxisVelocity) b) use past move tracking and
* store more moves (!) and store more context (e.g. bounce entry for
* center). c) combine both approaches, possibly use an interface to be
* set within SimpleEntry.
*/
// TODO: Adjust amount based on side conditions (center push or off center, distance to block top).
double amount = -1.0;
final BlockChangeEntry entryBelowY_POS = blockChangeTracker.getBlockChangeEntryMatchFlags(
data.blockChangeRef, tick, worldId, from.getBlockX(), from.getBlockY() - 1, from.getBlockZ(),
Direction.Y_POS, BlockProperties.F_BOUNCE25);
if (
// Center push.
entryBelowY_POS != null
// Off center push (2x 0.5(015) only, (sum below 1.015 ?)).
// Off center push.
|| thisMove.yDistance < 1.015 && from.matchBlockChangeMatchResultingFlags(blockChangeTracker,
data.blockChangeRef, Direction.Y_POS, Math.min(.415, thisMove.yDistance),
BlockProperties.F_BOUNCE25)
) {
// Always allow the double 0.505 move.
/*
* TODO: May detect the first 0.505 move to match preconditions
* better (roughly 2x 0.5, 0.0 -> 1.5, -0.few -> 1.389). One might
* also nail down to past y-position further. Also consider
* confining to horizontal speed envelope (is that even possible)?
*/
if (data.debug) {
debug(player, "checkPastStateBounceAscend: " + (entryBelowY_POS == null ? "off_center" : "center"));
debug(player, "Direct block push with bounce (" + (entryBelowY_POS == null ? "off_center)." : "center)."));
}
// TODO: Nail down to more precise side conditions for larger jumps, if possible.
// TODO: Adjust amount based on side conditions (center push or off center, distance to block top).
// TODO: Center push, without being hit by the block (2 below!) -> 0.5 off ground + 1.5 roughly !
// TODO: Push up, without being inside the pushed block (0.5 + 0.9x).
// TODO: Add two entries, split based on current yDistance?
amount = Math.min(Math.max(0.505, 1.0 + (double) from.getBlockY() - from.getY() + 1.515),
2.525); // TODO: EXACT MAGIC.
if (entryBelowY_POS != null) {
data.blockChangeRef.updateSpan(entryBelowY_POS);
}
}
// Center push while being on the top height of the pushed block already (or 0.5 above (!)).
if (
amount < 0.0
// TODO: Not sure about y-Distance.
// TODO: MAGIC EVERYWHERE
&& lastMove.toIsValid && lastMove.yDistance >= 0.0 && lastMove.yDistance <= 0.505
&& from.getY() - (double) from.getBlockY() == lastMove.yDistance // TODO: Margin?
) {
final BlockChangeEntry entry2BelowY_POS = blockChangeTracker.getBlockChangeEntryMatchFlags(
data.blockChangeRef, tick, worldId, from.getBlockX(), from.getBlockY() - 2, from.getBlockZ(),
Direction.Y_POS, BlockProperties.F_BOUNCE25);
if (entry2BelowY_POS != null
// TODO: Does off center push exist with this very case?
) {
if (data.debug) {
debug(player, "Foot position block push with bounce (" + (entry2BelowY_POS == null ? "off_center)." : "center)."));
}
amount = Math.min(Math.max(0.505, 1.0 + (double) from.getBlockY() - from.getY() + 1.515),
2.015 - lastMove.yDistance); // TODO: EXACT MAGIC.
if (entryBelowY_POS != null) {
data.blockChangeRef.updateSpan(entry2BelowY_POS);
}
}
}
// Finally add velocity if set.
if (amount >= 0.0) {
/*
* TODO: USE EXISTING velocity with bounce flag set first, then peek
* / add. (might while peek -> has bounce flag: remove velocity)
*/
final double amount = Math.min(Math.max(0.505, 1.0 + (double) from.getBlockY() - from.getY() + 1.515),
2.525); // TODO: EXACT MAGIC.
if (lastMove.toIsValid && lastMove.yDistance < 0.42 ||
data.peekVerticalVelocity(amount, 2, 3) == null) {
// (Could skip peek for low distances around 0.5.)
if (data.peekVerticalVelocity(amount, 2, 3) == null) {
/*
* TODO: Concepts for limiting... max amount based on side
* conditions such as block height+1.5, max coordinate, max
@ -1017,17 +1016,13 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
* past move tracking, or a sub-class of SimpleEntry with better
* access signatures including thisMove.
*/
/*
* TODO: Also account for current yDistance here? E.g. Add two
* entries, split based on current yDistance?
*/
final SimpleEntry vel = new SimpleEntry(tick, amount, FLAGS_VELOCITY_BOUNCE_BLOCK_MOVE_ASCEND, 4);
data.verticalBounce = vel;
data.useVerticalBounce(player);
/*
* TODO: Update span or not ... [could use a class that extends
* SimpleEntry but which also contains a block change id to update
* span with, upon using that entry?]
*/
if (entryBelowY_POS != null) {
data.blockChangeRef.updateSpan(entryBelowY_POS);
}
if (data.debug) {
debug(player, "checkPastStateBounceAscend: add velocity: " + vel);
}
@ -1053,12 +1048,6 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
*/
private boolean checkBounceEnvelope(final Player player, final PlayerLocation from, final PlayerLocation to,
final MovingData data, final MovingConfig cc) {
/*
* TODO: Likely not conform with getting pushed up, while outside of the
* strict envelope. The advantage of detecting that here could be the
* invalidation mechanics (also consider passable etc.), otherwise the
* move up might miss the already invalidated push up.
*/
return
// 0: Normal envelope (forestall NoFall).
(

View File

@ -15,6 +15,7 @@
package fr.neatmonster.nocheatplus.checks.moving.model;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.moving.velocity.SimpleEntry;
/**
* Include player specific data for a move.
@ -77,6 +78,12 @@ public class PlayerMoveData extends MoveData {
*/
public boolean mightBeMultipleMoves;
/**
* Just the used vertical velocity. Could be overridden multiple times
* during processing of moving checks.
*/
public SimpleEntry verVelUsed = null;
@Override
protected void resetBase() {
// Properties of the player.
@ -90,6 +97,7 @@ public class PlayerMoveData extends MoveData {
flyCheck = CheckType.UNKNOWN;
modelFlying = null;
mightBeMultipleMoves = false;
verVelUsed = null;
// Super class last, because it'll set valid to true in the end.
super.resetBase();
}

View File

@ -512,7 +512,9 @@ public class CreativeFly extends Check {
return Math.max(maximumHeight - 10.0, world.getMaxHeight());
}
private void outpuDebugMove(final Player player, final double hDistance, final double limitH, final double yDistance, final double limitV, final ModelFlying model, final List<String> tags, final MovingData data) {
private void outpuDebugMove(final Player player, final double hDistance, final double limitH,
final double yDistance, final double limitV, final ModelFlying model, final List<String> tags,
final MovingData data) {
final PlayerMoveData lastMove = data.playerMoves.getFirstPastMove();
StringBuilder builder = new StringBuilder(350);
final String dHDist = lastMove.toIsValid ? " (" + StringUtil.formatDiff(hDistance, lastMove.hDistance) + ")" : "";
@ -522,8 +524,8 @@ public class CreativeFly extends Check {
if (lastMove.toIsValid) {
builder.append(" , fdsq: " + StringUtil.fdec3.format(thisMove.distanceSquared / lastMove.distanceSquared));
}
if (data.verVelUsed != null) {
builder.append(" , vVelUsed: " + data.verVelUsed);
if (thisMove.verVelUsed != null) {
builder.append(" , vVelUsed: " + thisMove.verVelUsed);
}
builder.append(" , model: " + model.id);
if (!tags.isEmpty()) {

View File

@ -39,6 +39,7 @@ import fr.neatmonster.nocheatplus.checks.moving.model.LiftOffEnvelope;
import fr.neatmonster.nocheatplus.checks.moving.model.LocationData;
import fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveData;
import fr.neatmonster.nocheatplus.checks.moving.util.AuxMoving;
import fr.neatmonster.nocheatplus.checks.moving.velocity.VelocityFlags;
import fr.neatmonster.nocheatplus.checks.workaround.WRPT;
import fr.neatmonster.nocheatplus.compat.Bridge1_9;
import fr.neatmonster.nocheatplus.compat.BridgeEnchant;
@ -410,7 +411,8 @@ public class SurvivalFly extends Check {
// Silent set-back.
if (data.debug) {
tags.add("silentsbcobweb");
outputDebug(player, to, data, cc, hDistance, hAllowedDistance, hFreedom, yDistance, vAllowedDistance, fromOnGround, resetFrom, toOnGround, resetTo);
outputDebug(player, to, data, cc, hDistance, hAllowedDistance, hFreedom,
yDistance, vAllowedDistance, fromOnGround, resetFrom, toOnGround, resetTo, thisMove);
data.ws.setJustUsedIds(null);
}
return data.getSetBack(to);
@ -456,7 +458,8 @@ public class SurvivalFly extends Check {
// Debug output.
final int tagsLength;
if (data.debug) {
outputDebug(player, to, data, cc, hDistance, hAllowedDistance, hFreedom, yDistance, vAllowedDistance, fromOnGround, resetFrom, toOnGround, resetTo);
outputDebug(player, to, data, cc, hDistance, hAllowedDistance, hFreedom,
yDistance, vAllowedDistance, fromOnGround, resetFrom, toOnGround, resetTo, thisMove);
tagsLength = tags.size();
data.ws.setJustUsedIds(null);
}
@ -578,7 +581,7 @@ public class SurvivalFly extends Check {
// Prevent reset if coming from air (purpose of the flag).
data.sfLowJump = false;
}
if (hFreedom <= 0.0 && data.verVelUsed == null) {
if (hFreedom <= 0.0 && thisMove.verVelUsed == null) {
data.resetVelocityJumpPhase();
}
}
@ -1111,6 +1114,13 @@ public class SurvivalFly extends Check {
else if (lastMove.toIsValid && MagicAir.oddJunction(from, to, yDistance, yDistChange, yDistDiffEx, maxJumpGain, resetTo, thisMove, lastMove, data, cc)) {
// Several types of odd in-air moves, mostly with gravity near maximum, friction, medium change.
}
else if (thisMove.yDistance < 1.0 && thisMove.yDistance > 0.9
&& lastMove.yDistance >= 1.5 && data.sfJumpPhase <= 2
&& lastMove.verVelUsed != null
&& (lastMove.verVelUsed.flags & (VelocityFlags.ORIGIN_BLOCK_MOVE | VelocityFlags.ORIGIN_BLOCK_BOUNCE)) != 0) {
// Allow too strong decrease.
// TODO: Another magic check here? Route most checks through methods anyway?
}
else {
vDistRelVL = true;
}
@ -1199,7 +1209,8 @@ public class SurvivalFly extends Check {
// TODO: move into the in air checking above !?
if (!envelopeHack && !resetFrom && !resetTo) {
// "On-air" checks (vertical, already use velocity if needed).
vDistanceAboveLimit = Math.max(vDistanceAboveLimit, inAirChecks(now, from, to, hDistance, yDistance, lastMove, data, cc));
vDistanceAboveLimit = Math.max(vDistanceAboveLimit,
inAirChecks(now, from, to, hDistance, yDistance, thisMove, lastMove, data, cc));
}
// Block 'step' with yDistance between step height and minJumpGain (vdistrel and vdistsb should catch the rest).
@ -1298,7 +1309,10 @@ public class SurvivalFly extends Check {
* @param cc
* @return
*/
private double inAirChecks(final long now, final PlayerLocation from, final PlayerLocation to, final double hDistance, final double yDistance, final PlayerMoveData lastMove, final MovingData data, final MovingConfig cc) {
private double inAirChecks(final long now, final PlayerLocation from, final PlayerLocation to,
final double hDistance, final double yDistance,
final PlayerMoveData thisMove, final PlayerMoveData lastMove,
final MovingData data, final MovingConfig cc) {
double vDistanceAboveLimit = 0;
// y direction change detection.
@ -1319,7 +1333,7 @@ public class SurvivalFly extends Check {
// Allow adding 0.
data.vDistAcc.add((float) yDistance);
}
else if (data.verVelUsed == null) { // Only skip if just used.
else if (thisMove.verVelUsed == null) { // Only skip if just used.
// Here yDistance can be negative and positive.
// if (yDistance != 0.0) {
data.vDistAcc.add((float) yDistance);
@ -2017,11 +2031,13 @@ public class SurvivalFly extends Check {
* @param toOnGround
* @param resetTo
*/
private void outputDebug(final Player player, final PlayerLocation to, final MovingData data, final MovingConfig cc,
final double hDistance, final double hAllowedDistance, final double hFreedom, final double yDistance, final double vAllowedDistance,
final boolean fromOnGround, final boolean resetFrom, final boolean toOnGround, final boolean resetTo) {
private void outputDebug(final Player player, final PlayerLocation to,
final MovingData data, final MovingConfig cc,
final double hDistance, final double hAllowedDistance, final double hFreedom,
final double yDistance, final double vAllowedDistance,
final boolean fromOnGround, final boolean resetFrom, final boolean toOnGround, final boolean resetTo,
final PlayerMoveData thisMove) {
// TODO: Show player name once (!)
final PlayerMoveData thisMove = data.playerMoves.getCurrentMove();
final PlayerMoveData lastMove = data.playerMoves.getFirstPastMove();
final StringBuilder builder = new StringBuilder(500);
builder.append(CheckUtils.getLogMessagePrefix(player, type));
@ -2035,8 +2051,8 @@ public class SurvivalFly extends Check {
if (lastMove.toIsValid) {
builder.append(" , fdsq: " + StringUtil.fdec3.format(thisMove.distanceSquared / lastMove.distanceSquared));
}
if (data.verVelUsed != null) {
builder.append(" , vVelUsed: " + data.verVelUsed + " ");
if (thisMove.verVelUsed != null) {
builder.append(" , vVelUsed: " + thisMove.verVelUsed + " ");
}
data.addVerticalVelocity(builder);
// if (data.horizontalVelocityCounter > 0 || data.horizontalFreedom >= 0.001) {