mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2024-09-27 14:13:11 +02:00
[BLEEDING] Adjustments + more slime+piston support (incomplete).
There are typical cases to cover: * Extra falling height. * Fall damage where a slime block had been. Thus adding a specialized method for bounce (just foot position) instead of using the full bounds would be better, preferably just check within the MovingListener (set bounce / adjust velocity there).
This commit is contained in:
parent
06c2cadf7f
commit
9a6a370f1d
@ -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.SimpleEntry;
|
||||
import fr.neatmonster.nocheatplus.checks.workaround.WRPT;
|
||||
import fr.neatmonster.nocheatplus.compat.Bridge1_9;
|
||||
import fr.neatmonster.nocheatplus.compat.BridgeEnchant;
|
||||
@ -431,10 +432,12 @@ public class SurvivalFly extends Check {
|
||||
}
|
||||
|
||||
// Post-check recovery.
|
||||
if (useBlockChangeTracker && vDistanceAboveLimit > 0.0 && Math.abs(yDistance) <= 1.015) {
|
||||
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, data);
|
||||
double[] blockMoveResult = getVerticalBlockMoveResult(yDistance, from, to, tick, data);
|
||||
if (blockMoveResult != null) {
|
||||
vAllowedDistance = blockMoveResult[0];
|
||||
vDistanceAboveLimit = blockMoveResult[1];
|
||||
@ -659,31 +662,45 @@ public class SurvivalFly extends Check {
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
private double[] getVerticalBlockMoveResult(final double yDistance, final PlayerLocation from, final PlayerLocation to, final MovingData data) {
|
||||
/*
|
||||
* TODO: Once horizontal push is allowed too, a maxIdEntry has to be
|
||||
* passed as argument and data.updateBlockChangeReference has to be
|
||||
* called after processing all pushing. Return the new maxEntry if
|
||||
* updated, or the old one.
|
||||
*/
|
||||
private double[] getVerticalBlockMoveResult(final double yDistance,
|
||||
final PlayerLocation from, final PlayerLocation to,
|
||||
final int tick, final MovingData data) {
|
||||
// TODO: Allow push up to 1.0 (or 0.65 something) even beyond block borders, IF COVERED [adapt PlayerLocation].
|
||||
// TODO: Might have to allow pushing up to a distance of 1.0 if covered.
|
||||
// TODO: Cleanup todo.
|
||||
// TODO: Other conditions/filters ... ?
|
||||
// Push (/pull) up.
|
||||
if (yDistance > 0.0 && (yDistance <= 1.0
|
||||
// Extra condition for full blocks: slightly more possible.
|
||||
// Extreme case: 1.51 blocks up (details pending).
|
||||
|| yDistance <= 1.015 && to.getY() - to.getBlockY() < 0.015)) {
|
||||
// TODO: Other conditions? [some will be in passable later].
|
||||
if (from.matchBlockChange(blockChangeTracker, data.blockChangeRef, Direction.Y_POS, Math.min(yDistance, 1.0))) {
|
||||
tags.add("blkmv_y_pos");
|
||||
final double maxDistYPos = yDistance; //1.0 - (from.getY() - from.getBlockY()); // TODO: Margin ?
|
||||
return new double[]{maxDistYPos, 0.0};
|
||||
if (yDistance > 0.0) {
|
||||
if ((yDistance <= 1.0
|
||||
// Extra condition for full blocks: slightly more possible.
|
||||
// Extreme case: 1.51 blocks up (details pending).
|
||||
|| yDistance <= 1.015 && to.getY() - to.getBlockY() < 0.015)) {
|
||||
if (from.matchBlockChange(blockChangeTracker, data.blockChangeRef, Direction.Y_POS,
|
||||
Math.min(yDistance, 1.0))) {
|
||||
tags.add("blkmv_y_pos");
|
||||
final double maxDistYPos = yDistance; //1.0 - (from.getY() - from.getBlockY()); // TODO: Margin ?
|
||||
return new double[]{maxDistYPos, 0.0};
|
||||
}
|
||||
}
|
||||
// (No else.)
|
||||
if (yDistance <= 1.55) {
|
||||
// TODO: Edges ca. 0.5 (or 2x 0.5).
|
||||
// TODO: Center ca. 1.5. With falling height, values increase slightly.
|
||||
// Simplified: Always allow 1.5 or less with being pushed up by slime.
|
||||
// TODO:
|
||||
if (from.matchBlockChangeMatchResultingFlags(
|
||||
blockChangeTracker, data.blockChangeRef, Direction.Y_POS,
|
||||
Math.min(yDistance, 0.42), // Special limit.
|
||||
BlockProperties.F_BOUNCE25)) {
|
||||
tags.add("blkmv_y_pos_bounce");
|
||||
final double maxDistYPos = yDistance; //1.0 - (from.getY() - from.getBlockY()); // TODO: Margin ?
|
||||
// TODO: Set bounce effect or something !?
|
||||
// TODO: Bounce effect instead ?
|
||||
data.addVerticalVelocity(new SimpleEntry(tick, Math.max(0.515, yDistance - 0.5), 2));
|
||||
return new double[]{maxDistYPos, 0.0};
|
||||
}
|
||||
}
|
||||
}
|
||||
// Push (/pull) down.
|
||||
else if (yDistance < 0.0 && yDistance >= -1.0) {
|
||||
// TODO: Other conditions? [some will be in passable later].
|
||||
if (from.matchBlockChange(blockChangeTracker, data.blockChangeRef, Direction.Y_NEG, -yDistance)) {
|
||||
tags.add("blkmv_y_neg");
|
||||
final double maxDistYNeg = yDistance; // from.getY() - from.getBlockY(); // TODO: Margin ?
|
||||
|
@ -5,14 +5,16 @@ import fr.neatmonster.nocheatplus.utilities.location.RichBoundsLocation;
|
||||
|
||||
/**
|
||||
* Simple class for helping with query functionality. Reference a
|
||||
* BlockChangeEntry and contain more information, such as validity for
|
||||
* further use/effects. This is meant for storing the state of last-consumed
|
||||
* block change entries for a context within some data.
|
||||
* BlockChangeEntry and contain more information, such as validity for further
|
||||
* use/effects. This is meant for storing the state of last-consumed block
|
||||
* change entries for a context within some data.
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public class BlockChangeReference {
|
||||
// TODO: IBlockChangeReference ?
|
||||
|
||||
/*
|
||||
* TODO: public BlockChangeEntry firstUsedEntry = null; // Would the
|
||||
* span suffice? Consider using span + timing or just the span during
|
||||
@ -34,25 +36,28 @@ public class BlockChangeReference {
|
||||
/**
|
||||
* Indicate if the timing of the last entry is still regarded as valid.
|
||||
*/
|
||||
/*
|
||||
* TODO: Subject to change, switching to tick rather than id (ids can be
|
||||
* inverted, thus lock out paths).
|
||||
*/
|
||||
public boolean valid = false;
|
||||
|
||||
/**
|
||||
* Check if this reference can be updated with the given entry,
|
||||
* considering set validity information. By default, the given tick
|
||||
* either must be greater than the stored one, or the tick are the same
|
||||
* and valid is set to true. The internal state is not changed by
|
||||
* calling this.
|
||||
* Check if this reference can be updated with the given entry, considering
|
||||
* set validity information. By default, the given tick either must be
|
||||
* greater than the stored one, or the tick are the same and valid is set to
|
||||
* true. The internal state is not changed by calling this.
|
||||
*
|
||||
* @param entry
|
||||
* @return
|
||||
*/
|
||||
public boolean canUpdateWith(final BlockChangeEntry entry) {
|
||||
// Love access methods: return this.lastUsedEntry == null || entry.id > this.lastUsedEntry.id || entry.id == this.lastUsedEntry.id && valid;
|
||||
// TODO: There'll be a span perhaps.
|
||||
// Formerly: return this.lastUsedEntry == null || entry.id > this.lastUsedEntry.id || entry.id == this.lastUsedEntry.id && valid;
|
||||
// TODO: Consider: Allow the same tick if id is higher. (order of ids doesn't really help too much though)
|
||||
// TODO: Consider: A tick-tolerance value [needs storing the tick of setting/altering].
|
||||
// TODO: Consider keeping a map/set of used entries + allow reuse depending on context.
|
||||
/*
|
||||
* TODO: Alternative context def.: Hard invalidation via lastUsedEntry
|
||||
* and soft invalidation via TBA span. E.g. hard for on ground and
|
||||
* passable, soft for push/pull.
|
||||
*/
|
||||
// TODO: There'll be a span of validity, perhaps.
|
||||
/*
|
||||
* Using ticks seems more appropriate, as ids are not necessarily
|
||||
* ordered in a relevant way, if they reference the same tick. Even
|
||||
@ -98,7 +103,8 @@ public class BlockChangeReference {
|
||||
*/
|
||||
if (lastSpanEntry != null && (lastUsedEntry == null || lastSpanEntry.id > lastUsedEntry.id)) {
|
||||
lastUsedEntry = lastSpanEntry;
|
||||
if (to != null && to.isBlockIntersecting(lastSpanEntry.x, lastSpanEntry.y, lastSpanEntry.z)) {
|
||||
if (to != null && to.isBlockIntersecting(
|
||||
lastSpanEntry.x, lastSpanEntry.y, lastSpanEntry.z, lastSpanEntry.direction.blockFace)) {
|
||||
valid = true;
|
||||
}
|
||||
else {
|
||||
|
@ -35,6 +35,7 @@ import fr.neatmonster.nocheatplus.NCPAPIProvider;
|
||||
import fr.neatmonster.nocheatplus.components.location.IGetPosition;
|
||||
import fr.neatmonster.nocheatplus.components.registry.event.IGenericInstanceHandle;
|
||||
import fr.neatmonster.nocheatplus.logging.Streams;
|
||||
import fr.neatmonster.nocheatplus.utilities.CheckUtils;
|
||||
import fr.neatmonster.nocheatplus.utilities.TickTask;
|
||||
import fr.neatmonster.nocheatplus.utilities.ds.map.CoordHashMap;
|
||||
import fr.neatmonster.nocheatplus.utilities.ds.map.CoordMap;
|
||||
@ -63,13 +64,13 @@ import fr.neatmonster.nocheatplus.utilities.map.BlockProperties;
|
||||
public class BlockChangeTracker {
|
||||
|
||||
public static enum Direction {
|
||||
NONE,
|
||||
X_POS,
|
||||
X_NEG,
|
||||
Y_POS,
|
||||
Y_NEG,
|
||||
Z_POS,
|
||||
Z_NEG;
|
||||
NONE(BlockFace.SELF),
|
||||
X_POS(CheckUtils.matchBlockFace(1, 0, 0)),
|
||||
X_NEG(CheckUtils.matchBlockFace(-1, 0, 0)),
|
||||
Y_POS(CheckUtils.matchBlockFace(0, 1, 0)),
|
||||
Y_NEG(CheckUtils.matchBlockFace(0, -1, 0)),
|
||||
Z_POS(CheckUtils.matchBlockFace(0, 0, 1)),
|
||||
Z_NEG(CheckUtils.matchBlockFace(0, 0, -1));
|
||||
|
||||
public static Direction getDirection(final BlockFace blockFace) {
|
||||
final int x = blockFace.getModX();
|
||||
@ -96,6 +97,12 @@ public class BlockChangeTracker {
|
||||
return NONE;
|
||||
}
|
||||
|
||||
public final BlockFace blockFace;
|
||||
|
||||
private Direction(BlockFace blockFace) {
|
||||
this.blockFace = blockFace;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -332,6 +339,7 @@ public class BlockChangeTracker {
|
||||
// Add this block.
|
||||
addBlockChange(changeId, tick, worldNode, x, y, z, Direction.getDirection(blockFace),
|
||||
blockCache.getOrCreateBlockCacheNode(x, y, z, true));
|
||||
//DebugUtil.debug("Piston: " + Direction.getDirection(blockFace) + " " + x + "," + y +"," + z + " / " + blockCache.getTypeId(x, y, z)); // TODO: REMOVE
|
||||
}
|
||||
|
||||
/**
|
||||
@ -594,7 +602,7 @@ public class BlockChangeTracker {
|
||||
* @param matchFlags
|
||||
* Only blocks having previous states that have any flags in
|
||||
* common with matchFlags are considered for output. If
|
||||
* matchFlags is smaller than zero, the parameter is ignored.
|
||||
* matchFlags is zero, the parameter is ignored.
|
||||
* @return The matching entry, or null if there is no matching entry.
|
||||
*/
|
||||
public BlockChangeEntry getBlockChangeEntryMatchFlags(final BlockChangeReference ref, final int tick,
|
||||
@ -608,8 +616,12 @@ public class BlockChangeTracker {
|
||||
final LinkedList<BlockChangeEntry> entries = getValidBlockChangeEntries(tick, worldNode, x, y, z);
|
||||
if (entries != null) {
|
||||
for (final BlockChangeEntry entry : entries) {
|
||||
if ((ref == null || ref.canUpdateWith(entry) && (direction == null || entry.direction == direction))
|
||||
&& (matchFlags < 0 || (matchFlags & BlockProperties.getBlockFlags(entry.previousState.getId())) != 0)) {
|
||||
if ((ref == null
|
||||
|| ref.canUpdateWith(entry)
|
||||
&& (direction == null || entry.direction == direction))
|
||||
//
|
||||
&& (matchFlags == 0
|
||||
|| (matchFlags & BlockProperties.getBlockFlags(entry.previousState.getId())) != 0)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import fr.neatmonster.nocheatplus.NCPAPIProvider;
|
||||
@ -268,4 +269,20 @@ public class CheckUtils {
|
||||
return NCPAPIProvider.getNoCheatPlusAPI().getGenericInstance(Random.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the appropriate BlockFace.
|
||||
* @param x Exact increments.
|
||||
* @param y
|
||||
* @param z
|
||||
* @return
|
||||
*/
|
||||
public static BlockFace matchBlockFace(int x, int y, int z) {
|
||||
for (BlockFace blockFace : BlockFace.values()) {
|
||||
if (blockFace.getModX() == x && blockFace.getModY() == y && blockFace.getModZ() == z) {
|
||||
return blockFace;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import java.util.UUID;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import fr.neatmonster.nocheatplus.checks.moving.location.LocUtil;
|
||||
@ -1118,11 +1119,14 @@ public class RichBoundsLocation implements IGetBukkitLocation, IGetBlockPosition
|
||||
|
||||
/**
|
||||
* Check for tracked block changes, having moved a block into a certain
|
||||
* direction, using the full bounding box (pistons), only regarding blocks
|
||||
* having flags in common with matchFlags. BlockChangeReference.updateSpan
|
||||
* is called with the earliest entry found (updateFinal has to be called
|
||||
* extra). This is an opportunistic version without any consistency checking
|
||||
* done, just updating the span by the earliest entry found.
|
||||
* direction, confined to certain blocks hitting the player, using the full
|
||||
* bounding box (pistons), only regarding blocks having flags in common with
|
||||
* matchFlags. Thus not the replaced state at a position is regarded, but
|
||||
* the state that should result from a block having been pushed there.
|
||||
* BlockChangeReference.updateSpan is called with the earliest entry found
|
||||
* (updateFinal has to be called extra). This is an opportunistic version
|
||||
* without any consistency checking done, just updating the span by the
|
||||
* earliest entry found.
|
||||
*
|
||||
* @param blockChangeTracker
|
||||
* the block change tracker
|
||||
@ -1134,25 +1138,28 @@ public class RichBoundsLocation implements IGetBukkitLocation, IGetBlockPosition
|
||||
* The (always positive) distance to cover.
|
||||
* @param matchFlags
|
||||
* Only blocks with past states having any flags in common with
|
||||
* matchFlags. If matchFlags is smaller than zero, the parameter
|
||||
* is ignored.
|
||||
* matchFlags. If matchFlags is zero, the parameter is ignored.
|
||||
* @return Returns true, iff an entry was found.
|
||||
*/
|
||||
public boolean matchBlockChangeMatchFlags(final BlockChangeTracker blockChangeTracker,
|
||||
public boolean matchBlockChangeMatchResultingFlags(final BlockChangeTracker blockChangeTracker,
|
||||
final BlockChangeReference ref, final Direction direction, final double coverDistance,
|
||||
final long matchFlags) {
|
||||
// TODO: Remove this method (!). Use a specialized method (here or external) just for bounce.
|
||||
/*
|
||||
* TODO: Not sure with code duplication. Is it better to run
|
||||
* BlockChangeTracker.getBlockChangeMatchFlags for the other method too?
|
||||
*/
|
||||
// TODO: Intended use is bouncing off slime, thus need confine to foot level ?
|
||||
final int tick = TickTask.getTick();
|
||||
final UUID worldId = world.getUID();
|
||||
final int iMinX = Location.locToBlock(minX);
|
||||
final int iMaxX = Location.locToBlock(maxX);
|
||||
final int iMinY = Location.locToBlock(minY);
|
||||
final int iMaxY = Location.locToBlock(maxY);
|
||||
final int iMinZ = Location.locToBlock(minZ);
|
||||
final int iMaxZ = Location.locToBlock(maxZ);
|
||||
// Shift the entire search box to the opposite direction (if direction is given).
|
||||
final BlockFace blockFace = direction == null ? BlockFace.SELF : direction.blockFace;
|
||||
final int iMinX = Location.locToBlock(minX) - blockFace.getModX();
|
||||
final int iMaxX = Location.locToBlock(maxX) - blockFace.getModX();
|
||||
final int iMinY = Location.locToBlock(minY) - blockFace.getModY();
|
||||
final int iMaxY = Location.locToBlock(maxY) - blockFace.getModY();
|
||||
final int iMinZ = Location.locToBlock(minZ) - blockFace.getModZ();
|
||||
final int iMaxZ = Location.locToBlock(maxZ) - blockFace.getModZ();
|
||||
BlockChangeEntry minEntry = null;
|
||||
for (int x = iMinX; x <= iMaxX; x++) {
|
||||
for (int z = iMinZ; z <= iMaxZ; z++) {
|
||||
@ -1161,7 +1168,9 @@ public class RichBoundsLocation implements IGetBukkitLocation, IGetBlockPosition
|
||||
ref, tick, worldId, x, y, z, direction, matchFlags);
|
||||
if (entry != null && (minEntry == null || entry.id < minEntry.id)) {
|
||||
// Check vs. coverDistance, exclude cases where the piston can't push that far.
|
||||
if (coverDistance > 0.0 && coversDistance(x, y, z, direction, coverDistance)) {
|
||||
if (coverDistance > 0.0 && coversDistance(
|
||||
x + blockFace.getModX(), y + blockFace.getModY(), z + blockFace.getModZ(),
|
||||
direction, coverDistance)) {
|
||||
minEntry = entry;
|
||||
}
|
||||
}
|
||||
@ -1186,7 +1195,7 @@ public class RichBoundsLocation implements IGetBukkitLocation, IGetBlockPosition
|
||||
* the y
|
||||
* @param z
|
||||
* the z
|
||||
* @return true, if is block intersecting
|
||||
* @return true, if the block is intersecting
|
||||
*/
|
||||
public boolean isBlockIntersecting(final int x, final int y, final int z) {
|
||||
return CollisionUtil.intersectsBlock(minX, maxX, x)
|
||||
@ -1194,6 +1203,26 @@ public class RichBoundsLocation implements IGetBukkitLocation, IGetBlockPosition
|
||||
&& CollisionUtil.intersectsBlock(minZ, maxZ, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test, if either of two blocks intersects the bounding box, if assuming
|
||||
* full bounds.
|
||||
*
|
||||
* @param x
|
||||
* the x
|
||||
* @param y
|
||||
* the y
|
||||
* @param z
|
||||
* the z
|
||||
* @param blockFace
|
||||
* An additional block to check from the coordinates into that
|
||||
* direction.
|
||||
* @return true, if either block is intersecting
|
||||
*/
|
||||
public boolean isBlockIntersecting(final int x, final int y, final int z, final BlockFace blockFace) {
|
||||
return isBlockIntersecting(x, y, z)
|
||||
|| isBlockIntersecting(x + blockFace.getModX(), y + blockFace.getModY(), z + blockFace.getModZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a block fully moved into that direction can move the player by
|
||||
* coverDistance.
|
||||
|
Loading…
Reference in New Issue
Block a user