Skip to content

Commit 3198615

Browse files
committed
Fix riptide-equipped trident release not being detected; fix elytra + riptide; attempt to fix illegalsprint false positives.
* Order of operations for gliding with an elytra while riptiding was wrong: when gliding, riptide motion is added before. Only question that remains is: before stuck speed or after? * For the tridentRelease flag, the moving trace was resetting the flag too early: as a fix, simply reset the flag manually instead of in the resetBase. * Some notes/comments
1 parent 125a239 commit 3198615

File tree

4 files changed

+29
-26
lines changed

4 files changed

+29
-26
lines changed

NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingData.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import org.bukkit.entity.Entity;
2424
import org.bukkit.entity.EntityType;
2525
import org.bukkit.entity.Player;
26-
import org.bukkit.event.player.PlayerInputEvent;
2726
import org.bukkit.event.player.PlayerMoveEvent;
2827

2928
import fr.neatmonster.nocheatplus.NCPAPIProvider;
@@ -176,7 +175,7 @@ public VehicleMoveData call() throws Exception {
176175
}, 2);
177176
/**
178177
* Track the inputs of the player (WASD, space bar, sprinting and jumping). <br>
179-
* The field is updated on {@link org.bukkit.event.player.PlayerMoveEvent} under split moves processor.<p>
178+
* The field is updated on {@link org.bukkit.event.player.PlayerMoveEvent}s under split moves processor.<p>
180179
* This field is the one you should use to read input information during a PlayerMoveEvent instead of {@link Player#getCurrentInput()} alone, as it is kept synchronized with the correct movement, in case Bukkit happens to skip PlayerMoveEvents,
181180
* causing a de-synchronization between inputs and movements (see comment in {@link MovingListener#onPlayerMove(PlayerMoveEvent)} and {@link PlayerMoveData#multiMoveCount}).<p>
182181
* This data is stored in MovingData instead of the Moving trace, as the latter may be invalidated, overridden or otherwise wiped out, while the input state is still valid and needed for the next move(s); it is not suitable for long-term storage.

NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/model/PlayerMoveData.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public class PlayerMoveData extends MoveData {
4646
/** Represents how far the player is submerged in water. Set with {@link fr.neatmonster.nocheatplus.utilities.map.BlockProperties#getVerticalFrictionFactor(LivingEntity, Location, double, PlayerMoveData)} */
4747
public double submergedWaterHeight;
4848

49+
/** Sets whether the player has just released a trident with riptide. Set on {@link org.bukkit.event.player.PlayerRiptideEvent}. */
4950
public boolean tridentRelease;
5051

5152
/**
@@ -57,7 +58,8 @@ public class PlayerMoveData extends MoveData {
5758

5859
/**
5960
* Indicates that this movement has/should have been slowed down due to the player hitting an entity (sprinting will be reset as well).<br>
60-
* Mostly intended to be used for the h-speed prediction.
61+
* Mostly intended to be used for the h-speed prediction.<br>
62+
* Set in the {@link fr.neatmonster.nocheatplus.checks.fight.FightListener}
6163
*/
6264
public boolean hasAttackSlowDown;
6365

@@ -70,7 +72,7 @@ public class PlayerMoveData extends MoveData {
7072
public double xAllowedDistance;
7173

7274
/**
73-
* The collision oon the X axis that has been set in this movement by SurvivalFly.
75+
* The collision on the X axis that has been set in this movement by SurvivalFly.
7476
* Prior to version 1.21.2, this was set only if the theoretical speed prediction to set in this movement was found; or in other words, only if the player isn't cheating.
7577
* On 1.21.2 and above, this is always set
7678
* @see PlayerMoveData#hasImpulse
@@ -206,7 +208,6 @@ protected void resetBase() {
206208
submergedLavaHeight = 0.0;
207209
submergedWaterHeight = 0.0;
208210
isGliding = false;
209-
tridentRelease = false;
210211
forwardImpulse = PlayerKeyboardInput.ForwardDirection.NONE;
211212
strafeImpulse = PlayerKeyboardInput.StrafeDirection.NONE;
212213
// Properties involving the environment.

NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/SurvivalFly.java

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ public Location check(final Player player, final PlayerLocation from, final Play
124124
final boolean debug = pData.isDebugActive(type);
125125
final PlayerMoveData thisMove = data.playerMoves.getCurrentMove();
126126
final PlayerMoveData lastMove = data.playerMoves.getFirstPastMove();
127+
final CombinedData cData = pData.getGenericInstance(CombinedData.class);
127128
/* Regular and past fromOnGround */
128129
final boolean fromOnGround = from.isOnGround() || useBlockChangeTracker && from.isOnGroundOpportune(cc.yOnGround, 0L, blockChangeTracker, data.blockChangeRef, tick);
129130
/* Regular and past toOnGround */
@@ -328,11 +329,13 @@ else if (resetFrom) {
328329
data.lastLevitationLevel = !Double.isInfinite(Bridge1_9.getLevitationAmplifier(player)) ? Bridge1_9.getLevitationAmplifier(player) + 1 : 0.0;
329330
data.lastGravity = data.nextGravity;
330331
data.lastCollidingEntitiesLocations = CollisionUtil.getCollidingEntitiesLocations(player);
331-
final CombinedData cData = pData.getGenericInstance(CombinedData.class);
332332
cData.wasSprinting = pData.isSprinting();
333333
cData.wasPressingShift = pData.isShiftKeyPressed();
334334
cData.wasSlowFalling = !Double.isInfinite(Bridge1_13.getSlowfallingAmplifier(player));
335335
cData.wasLevitating = !Double.isInfinite(Bridge1_9.getLevitationAmplifier(player));
336+
if (thisMove.tridentRelease) {
337+
thisMove.tridentRelease = false;
338+
}
336339
// Log tags added after violation handling.
337340
if (debug && tags.size() > tagsLength) {
338341
logPostViolationTags(player);
@@ -474,6 +477,16 @@ private double[] processGliding(final PlayerLocation from, final PlayerLocation
474477
// Reset speed if judged to be negligible.
475478
checkNegligibleMomentum(pData, thisMove);
476479
checkNegligibleMomentumVertical(pData, thisMove);
480+
// Yes, players can glide and riptide at the same time, increasing speed at a faster rate than chunks can load...
481+
// Surely a questionable decision on Mojang's part.
482+
// NOTE: For the elytra, this has to be done before applying gravity and other motion changes.
483+
if (thisMove.tridentRelease) {
484+
Vector riptideVelocity = to.getRiptideVelocity(false); // Cannot glide while on ground, so no need to check for it.
485+
// Fortunately, we do not have to account for onGround push here, as gliding does not work on ground.
486+
thisMove.xAllowedDistance += riptideVelocity.getX();
487+
thisMove.yAllowedDistance += riptideVelocity.getY();
488+
thisMove.zAllowedDistance += riptideVelocity.getZ();
489+
}
477490
// TODO: Reduce verbosity (at least, make it easier to look at)
478491
Vector viewVector = TrigUtil.getLookingDirection(to, player);
479492
float radianPitch = to.getPitch() * TrigUtil.toRadians;
@@ -522,22 +535,12 @@ private double[] processGliding(final PlayerLocation from, final PlayerLocation
522535
thisMove.xAllowedDistance *= 0.99;
523536
thisMove.yAllowedDistance *= data.lastFrictionVertical;
524537
thisMove.zAllowedDistance *= 0.99;
525-
526538
// Stuck-speed with the updated multiplier (both at the end)
527539
if (TrigUtil.lengthSquared(data.nextStuckInBlockHorizontal, data.nextStuckInBlockVertical, data.nextStuckInBlockHorizontal) > 1.0E-7) {
528540
thisMove.xAllowedDistance *= (double) data.nextStuckInBlockHorizontal;
529541
thisMove.yAllowedDistance *= (double) data.nextStuckInBlockVertical;
530542
thisMove.zAllowedDistance *= (double) data.nextStuckInBlockHorizontal;
531543
}
532-
// Yes, players can glide and riptide at the same time, increasing speed at a faster rate than chunks can load...
533-
// Surely a questionable decision on Mojang's part.
534-
if (thisMove.tridentRelease) {
535-
Vector riptideVelocity = to.getRiptideVelocity(false); // Cannot glide while on ground, so no need to check for it.
536-
// Fortunately, we do not have to account for onGround push here, as gliding does not work on ground.
537-
thisMove.xAllowedDistance += riptideVelocity.getX();
538-
thisMove.yAllowedDistance += riptideVelocity.getY();
539-
thisMove.zAllowedDistance += riptideVelocity.getZ();
540-
}
541544
// Collisions last.
542545
Vector collisionVector = from.collide(new Vector(thisMove.xAllowedDistance, thisMove.yAllowedDistance, thisMove.zAllowedDistance), fromOnGround || thisMove.touchedGroundWorkaround, from.getBoundingBox());
543546
thisMove.collideX = collisionVector.getX() != thisMove.xAllowedDistance;
@@ -676,7 +679,9 @@ private double[] prepareSpeedEstimation(final PlayerLocation from, final PlayerL
676679
return new double[]{thisMove.hAllowedDistance, hDistanceAboveLimit};
677680
}
678681

679-
boolean onGround = !forceSetOffGround && (from.isOnGround() || lastMove.toIsValid && lastMove.yDistance <= 0.0 && lastMove.from.onGround || lastMove.yDistance < 0.0 && thisMove.fromLostGround || forceSetOnGround);
682+
boolean onGround = from.isOnGround() || lastMove.toIsValid && lastMove.yDistance <= 0.0 && lastMove.from.onGround || lastMove.yDistance < 0.0 && thisMove.fromLostGround || forceSetOnGround;
683+
// Override ground status if needed.
684+
if (forceSetOffGround) onGround = false;
680685
/* All moves are assumed to be predictable, unless there are technical limitations / bugs / glitches that we cannot solve */
681686
boolean isPredictable;
682687
//////////////////////////////////////////////////////////////
@@ -737,7 +742,7 @@ else if (from.isInLava()) {
737742
else hDistanceAboveLimit = handleUnpredictableMove(thisMove, cc.survivalFlyStrictHorizontal);
738743
if (hDistanceAboveLimit > 0.0) {
739744
tags.add("hdistrel");
740-
//if (debug) player.sendMessage("c/e: " + StringUtil.fdec6.format(thisMove.hDistance) + " / " + StringUtil.fdec6.format(thisMove.hAllowedDistance));
745+
if (debug) player.sendMessage("c/e: " + StringUtil.fdec6.format(thisMove.hDistance) + " / " + StringUtil.fdec6.format(thisMove.hAllowedDistance));
741746
}
742747
return new double[]{thisMove.hAllowedDistance, hDistanceAboveLimit};
743748
}
@@ -856,7 +861,7 @@ private boolean estimateNextSpeed(final Player player, float movementSpeed, fina
856861
}
857862
// If impulses don't need to be inferred from the prediction, illegal sprinting checks can be performed here.
858863
if (BridgeMisc.isWASDImpulseKnown(player) && pData.isSprinting()
859-
&& (data.input.getForwardDir() != ForwardDirection.FORWARD
864+
&& (data.input.getForwardDir() != ForwardDirection.FORWARD && data.input.getStrafeDir() != StrafeDirection.NONE && data.input.getForwardDir() != ForwardDirection.NONE
860865
|| player.getFoodLevel() <= 5) // must be checked here as well (besides on toggle sprinting) because players will immediately lose the ability to sprint if food level drops below 5
861866
) {
862867
// || inputs[i].getForward() < 0.8 // hasEnoughImpulseToStartSprinting, in LocalPlayer,java -> aiStep()
@@ -1039,9 +1044,6 @@ private boolean estimateNextSpeed(final Player player, float movementSpeed, fina
10391044
thisMove.xAllowedDistance += (double) (-TrigUtil.sin(to.getYaw() * TrigUtil.toRadians) * Magic.BUNNYHOP_BOOST);
10401045
thisMove.zAllowedDistance += (double) (TrigUtil.cos(to.getYaw() * TrigUtil.toRadians) * Magic.BUNNYHOP_BOOST);
10411046
thisMove.bunnyHop = true;
1042-
if (!BridgeMisc.isWASDImpulseKnown(player) && PhysicsEnvelope.isVerticallyConstricted(from, to, pData)) {
1043-
isPredictable = false;
1044-
}
10451047
tags.add("bunnyhop");
10461048
}
10471049

@@ -1162,9 +1164,9 @@ else if (lastMove.from.inLava) {
11621164
thisMove.hasImpulse = AlmostBoolean.match(input.getForwardDir() != ForwardDirection.NONE || input.getStrafeDir() != StrafeDirection.NONE);
11631165
thisMove.strafeImpulse = input.getStrafeDir();
11641166
thisMove.forwardImpulse = input.getForwardDir();
1165-
/*if (debug) {
1167+
if (debug) {
11661168
player.sendMessage("[SurvivalFly] (postPredict) Direction: " + input.getForwardDir() +" | "+ input.getStrafeDir());
1167-
}*/
1169+
}
11681170
// If-else instead of an early return... Matter of preference. This makes code slightly easier to look at, as it avoids yet another indentation
11691171
return isPredictable;
11701172
}
@@ -1305,7 +1307,8 @@ True, if the offset between predicted and actual speed is smaller than the accur
13051307
if (found) {
13061308
// These checks must be performed ex-post because they rely on data that is set after the prediction.
13071309
if (pData.isSprinting()
1308-
&& (theorInputs[i].getForwardDir() != ForwardDirection.FORWARD || player.getFoodLevel() <= 5)) {
1310+
&& (theorInputs[i].getForwardDir() != ForwardDirection.FORWARD && theorInputs[i].getStrafeDir() != StrafeDirection.NONE && theorInputs[i].getForwardDir() != ForwardDirection.NONE
1311+
|| player.getFoodLevel() <= 5)) {
13091312
tags.add("illegalsprint");
13101313
Improbable.check(player, (float) thisMove.hDistance, System.currentTimeMillis(), "moving.survivalfly.illegalsprint", pData);
13111314
// Keep looping

NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/location/PlayerLocation.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public Player getPlayer() {
6666

6767
/**
6868
* Straw-man method to account for this specific bug: <a href="https://bugs.mojang.com/browse/MC-2404">...</a>
69-
* Should not be used outside its intended context (sneaking on edges), or if vanilla uses it.
69+
* Should not be used outside its intended context (sneaking on edges), or if vanilla uses it elsewhere.
7070
*/
7171
public boolean isAboveGround() {
7272
final IPlayerData pData = DataManager.getPlayerData(player);

0 commit comments

Comments
 (0)