mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2024-06-26 06:14:42 +02:00
[BLEEDING] Switch implementation for moving.passable.
Switch to AxisTracing instead of RayTracing. This means most workarounds are removed, including some (legacy) performance saving tweaks.
This commit is contained in:
parent
ec333fb432
commit
2ff0076e69
|
@ -39,7 +39,7 @@ public class Passable extends Check {
|
|||
|
||||
// TODO: Make this configurable once a working set of settings has been found.
|
||||
// TODO: Once made configurable... intense testing... and test cases.
|
||||
private static boolean rt_legacy = true;
|
||||
private static boolean rt_legacy = false;
|
||||
// TODO: rt_xzFactor = 1.0; // Problems: Doors, fences.
|
||||
private static double rt_xzFactor = 0.98;
|
||||
// TODO: Test bumping head into things.
|
||||
|
@ -68,56 +68,49 @@ public class Passable extends Check {
|
|||
|
||||
public Location check(final Player player, final PlayerLocation from, final PlayerLocation to, final MovingData data, final MovingConfig cc)
|
||||
{
|
||||
// TODO: if (!from.isSameCoords(loc)) {...check passable for loc -> from !?... + sf etc too?}
|
||||
// TODO: Future: Account for the players bounding box? [test very-strict setting for at least the end points...]
|
||||
// TODO: WAT: if (!from.isSameCoords(loc)) {...check passable for loc -> from !?... + sf etc too?}
|
||||
|
||||
|
||||
// TODO: Distinguish feet vs. box.
|
||||
|
||||
String tags = "";
|
||||
// Block distances (sum, max) for from-to (not for loc!).
|
||||
final int manhattan = from.manhattan(to);
|
||||
// Skip moves inside of ignored blocks right away [works as long as we only check between foot-locations].
|
||||
if (manhattan <= 1 && BlockProperties.isPassable(from.getTypeId())) {
|
||||
// TODO: Monitor: BlockProperties.isPassable checks slightly different than before.
|
||||
if (manhattan == 0){
|
||||
return null;
|
||||
} else {
|
||||
// manhattan == 1
|
||||
if (BlockProperties.isPassable(to.getTypeId())) {
|
||||
|
||||
if (rt_legacy) {
|
||||
// Skip moves inside of ignored blocks right away [works as long as we only check between foot-locations].
|
||||
if (manhattan <= 1 && BlockProperties.isPassable(from.getTypeId())) {
|
||||
// TODO: Monitor: BlockProperties.isPassable checks slightly different than before.
|
||||
if (manhattan == 0){
|
||||
return null;
|
||||
} else {
|
||||
// manhattan == 1
|
||||
if (BlockProperties.isPassable(to.getTypeId())) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean toPassable = to.isPassable();
|
||||
// General condition check for using ray-tracing.
|
||||
if (toPassable && cc.passableRayTracingCheck && (!cc.passableRayTracingBlockChangeOnly || manhattan > 0)) {
|
||||
setNormalMargins(rayTracing, from);
|
||||
rayTracing.set(from, to);
|
||||
rayTracing.loop();
|
||||
if (rayTracing.collides() || rayTracing.getStepsDone() >= rayTracing.getMaxSteps()) {
|
||||
if (data.debug) {
|
||||
debugExtraCollisionDetails(player, rayTracing, "initial");
|
||||
}
|
||||
final int maxBlockDist = manhattan <= 1 ? manhattan : from.maxBlockDist(to);
|
||||
if (maxBlockDist <= 1 && rayTracing.getStepsDone() == 1 && !from.isPassable()) {
|
||||
// Redo ray-tracing for moving out of blocks.
|
||||
if (collidesIgnoreFirst(from, to)) {
|
||||
toPassable = false;
|
||||
tags = "raytracing_2x_";
|
||||
if (data.debug) {
|
||||
debugExtraCollisionDetails(player, rayTracing, "ingoreFirst");
|
||||
}
|
||||
}
|
||||
else if (data.debug) {
|
||||
debug(player, "Allow moving out of a block.");
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (!allowsSplitMove(from, to, manhattan, data)) {
|
||||
toPassable = false;
|
||||
tags = "raytracing_";
|
||||
}
|
||||
if ((!rt_legacy || toPassable) && cc.passableRayTracingCheck
|
||||
&& (!cc.passableRayTracingBlockChangeOnly || manhattan > 0)) {
|
||||
final String newTag;
|
||||
if (rt_legacy) {
|
||||
newTag = checkRayTracingLegacy(player, from, to, manhattan, data, cc);
|
||||
if (newTag != null) {
|
||||
toPassable = false;
|
||||
tags = newTag;
|
||||
}
|
||||
}
|
||||
else {
|
||||
newTag = checkRayTracing(player, from, to, manhattan, data, cc);
|
||||
if (newTag != null) {
|
||||
// Direct return.
|
||||
return potentialViolation(player, from, to, manhattan, tags, data, cc);
|
||||
}
|
||||
}
|
||||
// TODO: Future: If accuracy is demanded, also check the head position (or bounding box right away).
|
||||
rayTracing.cleanup();
|
||||
}
|
||||
|
||||
// TODO: Checking order: If loc is not the same as from, a quick return here might not be wanted.
|
||||
|
@ -127,11 +120,68 @@ public class Passable extends Check {
|
|||
data.passableVL *= 0.99;
|
||||
return null;
|
||||
} else {
|
||||
return potentialViolation(player, from, to, manhattan, tags, data, cc);
|
||||
return potentialViolationLegacy(player, from, to, manhattan, tags, data, cc);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String checkRayTracing(final Player player, final PlayerLocation from, final PlayerLocation to,
|
||||
final int manhattan, final MovingData data, final MovingConfig cc) {
|
||||
String tags = null;
|
||||
setNormalMargins(rayTracing, from);
|
||||
rayTracing.set(from, to);
|
||||
rayTracing.setIgnoreInitiallyColliding(true);
|
||||
//rayTracing.setCutOppositeDirectionMargin(true);
|
||||
rayTracing.loop();
|
||||
rayTracing.setIgnoreInitiallyColliding(false);
|
||||
//rayTracing.setCutOppositeDirectionMargin(false);
|
||||
if (rayTracing.collides()) {
|
||||
tags = "raytracing_collide_";
|
||||
}
|
||||
else if (rayTracing.getStepsDone() >= rayTracing.getMaxSteps()) {
|
||||
tags = "raytracing_maxsteps_";
|
||||
}
|
||||
if (data.debug) {
|
||||
debugExtraCollisionDetails(player, rayTracing, "std");
|
||||
}
|
||||
rayTracing.cleanup();
|
||||
return tags;
|
||||
}
|
||||
|
||||
private String checkRayTracingLegacy(final Player player, final PlayerLocation from, final PlayerLocation to,
|
||||
final int manhattan, final MovingData data, final MovingConfig cc) {
|
||||
setNormalMargins(rayTracing, from);
|
||||
rayTracing.set(from, to);
|
||||
rayTracing.loop();
|
||||
String tags = null;
|
||||
if (rayTracing.collides() || rayTracing.getStepsDone() >= rayTracing.getMaxSteps()) {
|
||||
if (data.debug) {
|
||||
debugExtraCollisionDetails(player, rayTracing, "legacy");
|
||||
}
|
||||
final int maxBlockDist = manhattan <= 1 ? manhattan : from.maxBlockDist(to);
|
||||
if (maxBlockDist <= 1 && rayTracing.getStepsDone() == 1 && !from.isPassable()) {
|
||||
// Redo ray-tracing for moving out of blocks.
|
||||
if (collidesIgnoreFirst(from, to)) {
|
||||
tags = "raytracing_2x_";
|
||||
if (data.debug) {
|
||||
debugExtraCollisionDetails(player, rayTracing, "ingoreFirst");
|
||||
}
|
||||
}
|
||||
else if (data.debug) {
|
||||
debug(player, "Allow moving out of a block.");
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (!allowsSplitMove(from, to, manhattan, data)) {
|
||||
tags = "raytracing_";
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: Future: If accuracy is demanded, also check the head position (or bounding box right away).
|
||||
rayTracing.cleanup();
|
||||
return tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default/normal margins.
|
||||
* @param rayTracing
|
||||
|
@ -141,8 +191,44 @@ public class Passable extends Check {
|
|||
rayTracing.setMargins(from.getEyeHeight() * rt_heightFactor, from.getWidth() / 2.0 * rt_xzFactor); // max from/to + resolution ?
|
||||
}
|
||||
|
||||
private Location potentialViolation(final Player player, final PlayerLocation from, final PlayerLocation to, final int manhattan, String tags, final MovingData data, final MovingConfig cc) {
|
||||
/**
|
||||
* Axis-wise ray-tracing violation skipping conditions.
|
||||
*
|
||||
* @param player
|
||||
* @param from
|
||||
* @param to
|
||||
* @param manhattan
|
||||
* @param tags
|
||||
* @param data
|
||||
* @param cc
|
||||
* @return
|
||||
*/
|
||||
private Location potentialViolation(final Player player,
|
||||
final PlayerLocation from, final PlayerLocation to, final int manhattan,
|
||||
String tags, final MovingData data, final MovingConfig cc) {
|
||||
|
||||
// TODO: Might need the workaround for fences.
|
||||
|
||||
return actualViolation(player, from, to, tags, data, cc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Legacy skipping conditions, before triggering an actual violation.
|
||||
*
|
||||
* @param player
|
||||
* @param from
|
||||
* @param to
|
||||
* @param manhattan
|
||||
* @param tags
|
||||
* @param data
|
||||
* @param cc
|
||||
* @return
|
||||
*/
|
||||
private Location potentialViolationLegacy(final Player player,
|
||||
final PlayerLocation from, final PlayerLocation to, final int manhattan,
|
||||
String tags, final MovingData data, final MovingConfig cc) {
|
||||
// Moving into a block, possibly a violation.
|
||||
// TODO: Do account for settings and ray-tracing here.
|
||||
|
||||
// First check if the player is moving from a passable location.
|
||||
// If not, the move might still be allowed, if moving inside of the same block, or from and to have head position passable.
|
||||
|
@ -163,21 +249,27 @@ public class Passable extends Check {
|
|||
// (Mind that this can be the case on the same block theoretically.)
|
||||
// Keep loc as set-back.
|
||||
// }
|
||||
else if (manhattan == 1 && to.isBlockAbove(from) && BlockProperties.isPassable(from.getBlockCache(), from.getX(), from.getY() + player.getEyeHeight(), from.getZ(), from.getTypeId(from.getBlockX(), Location.locToBlock(from.getY() + player.getEyeHeight()), from.getBlockZ()))) {
|
||||
else if (manhattan == 1 && to.isBlockAbove(from)
|
||||
&& BlockProperties.isPassable(from.getBlockCache(), from.getX(), from.getY() + player.getEyeHeight(), from.getZ(), from.getTypeId(from.getBlockX(), Location.locToBlock(from.getY() + player.getEyeHeight()), from.getBlockZ()))) {
|
||||
// else if (to.isBlockAbove(from) && BlockProperties.isPassableExact(from.getBlockCache(), from.getX(), from.getY() + player.getEyeHeight(), from.getZ(), from.getTypeId(from.getBlockX(), Location.locToBlock(from.getY() + player.getEyeHeight()), from.getBlockZ()))) {
|
||||
// Allow the move up if the head is free.
|
||||
// TODO: Better distinguish ray-tracing (through something thin) or check to-head-passable too?
|
||||
return null;
|
||||
}
|
||||
else if (manhattan > 0) {
|
||||
// Otherwise keep from as set-back.
|
||||
tags += "cross";
|
||||
}
|
||||
else{
|
||||
// All blocks are the same, allow the move.
|
||||
else {
|
||||
// manhattan == 0
|
||||
// TODO: Even legacy ray-tracing will now account for actual initial collision.
|
||||
return null;
|
||||
}
|
||||
|
||||
return actualViolation(player, from, to, tags, data, cc);
|
||||
}
|
||||
|
||||
private Location actualViolation(final Player player, final PlayerLocation from, final PlayerLocation to,
|
||||
final String tags, final MovingData data, final MovingConfig cc) {
|
||||
Location setBackLoc = null; // Alternative to from.getLocation().
|
||||
|
||||
// Prefer the set-back location from the data.
|
||||
|
@ -188,8 +280,6 @@ public class Passable extends Check {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: set data.set-back ? or something: still some aji here.
|
||||
|
||||
// Return the reset position.
|
||||
data.passableVL += 1d;
|
||||
final ViolationData vd = new ViolationData(this, player, data.passableVL, 1, cc.passableActions);
|
||||
|
@ -290,6 +380,13 @@ public class Passable extends Check {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug only if colliding.
|
||||
*
|
||||
* @param player
|
||||
* @param rayTracing
|
||||
* @param tag
|
||||
*/
|
||||
private void debugExtraCollisionDetails(Player player, ICollidePassable rayTracing, String tag) {
|
||||
if (rayTracing.collides()) {
|
||||
debug(player, "Raytracing collision (" + tag + "): " + rayTracing.getCollidingAxis());
|
||||
|
|
|
@ -3154,6 +3154,40 @@ public class BlockProperties {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the bounding box collides with a block (passable + accounting
|
||||
* for workarounds).
|
||||
*
|
||||
* @param access
|
||||
* @param minX
|
||||
* @param minY
|
||||
* @param minZ
|
||||
* @param maxX
|
||||
* @param maxY
|
||||
* @param maxZ
|
||||
* @return
|
||||
*/
|
||||
public static final boolean isPassableBox(final BlockCache access,
|
||||
final double minX, final double minY, final double minZ,
|
||||
final double maxX, final double maxY, final double maxZ) {
|
||||
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);
|
||||
for (int x = iMinX; x <= iMaxX; x++) {
|
||||
for (int z = iMinZ; z <= iMaxZ; z++) {
|
||||
for (int y = iMinY; y <= iMaxY; y++) {
|
||||
if (!isPassableBox(access, x, y, z, minX, minY, minZ, maxX, maxY, maxZ)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the block coordinates that are colliding via a isPassableBox check
|
||||
* for the given bounds to the given container.
|
||||
|
|
|
@ -86,6 +86,9 @@ public class RichBoundsLocation implements IGetBukkitLocation, IGetBlockPosition
|
|||
/** Simple test if the exact position is passable. */
|
||||
Boolean passable = null;
|
||||
|
||||
/** Bounding box collides with blocks. */
|
||||
Boolean passableBox = null;
|
||||
|
||||
/** Is the player above stairs? */
|
||||
Boolean aboveStairs = null;
|
||||
|
||||
|
@ -756,12 +759,44 @@ public class RichBoundsLocation implements IGetBukkitLocation, IGetBlockPosition
|
|||
*/
|
||||
public boolean isPassable() {
|
||||
if (passable == null) {
|
||||
passable = BlockProperties.isPassable(blockCache, x, y, z, getTypeId());
|
||||
// passable = BlockProperties.isPassableExact(blockCache, x, y, z, getTypeId());
|
||||
if (isBlockFlagsPassable()) {
|
||||
passable = true;
|
||||
}
|
||||
else {
|
||||
passable = BlockProperties.isPassable(blockCache, x, y, z, getTypeId());
|
||||
//passable = BlockProperties.isPassableExact(blockCache, x, y, z, getTypeId());
|
||||
}
|
||||
}
|
||||
return passable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the bounding box is colliding (passable check with accounting for
|
||||
* workarounds).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isPassableBox() {
|
||||
// TODO: Might need a variation with margins as parameters.
|
||||
if (passableBox == null) {
|
||||
if (isBlockFlagsPassable()) {
|
||||
passableBox = true;
|
||||
}
|
||||
else if (passable != null && !passable) {
|
||||
passableBox = false;
|
||||
}
|
||||
else {
|
||||
// Fetch.
|
||||
passableBox = BlockProperties.isPassableBox(blockCache, minX, minY, minZ, maxX, maxY, maxZ);
|
||||
}
|
||||
}
|
||||
return passableBox;
|
||||
}
|
||||
|
||||
private boolean isBlockFlagsPassable() {
|
||||
return blockFlags != null && (blockFlags & (BlockProperties.F_SOLID | BlockProperties.F_GROUND)) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set block flags using yOnGround, unless already set. Check the maximally
|
||||
* used bounds for the block checking, to have flags ready for faster
|
||||
|
@ -907,6 +942,7 @@ public class RichBoundsLocation implements IGetBukkitLocation, IGetBlockPosition
|
|||
this.notOnGroundMaxY = other.notOnGroundMaxY;
|
||||
this.onGroundMinY = other.onGroundMinY;
|
||||
this.passable = other.passable;
|
||||
this.passableBox = other.passableBox;
|
||||
// Access methods.
|
||||
this.typeId = other.getTypeId();
|
||||
this.typeIdBelow = other.getTypeIdBelow();
|
||||
|
@ -957,7 +993,7 @@ public class RichBoundsLocation implements IGetBukkitLocation, IGetBlockPosition
|
|||
|
||||
// Reset cached values.
|
||||
typeId = typeIdBelow = data = null;
|
||||
aboveStairs = inLava = inWater = inWeb = onIce = onGround = onClimbable = passable = null;
|
||||
aboveStairs = inLava = inWater = inWeb = onIce = onGround = onClimbable = passable = passableBox = null;
|
||||
onGroundMinY = Double.MAX_VALUE;
|
||||
notOnGroundMaxY = Double.MIN_VALUE;
|
||||
blockFlags = null;
|
||||
|
|
|
@ -180,6 +180,13 @@ public abstract class AxisTracing implements ICollide, ISetMargins {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean shouldCheckForIgnoredBlocks() {
|
||||
return ignoreInitiallyColliding && !ignoredBlocks.isEmpty();
|
||||
}
|
||||
|
||||
private boolean isBlockIgnored(final int x, final int y, final int z) {
|
||||
return ignoredBlocks.containsBlockPosition(x, y, z);
|
||||
}
|
||||
|
||||
private void runAxisY(final double xIn, final double yIn, final double zIn) {
|
||||
// Skip if there is nothing to iterate.
|
||||
|
@ -218,10 +225,10 @@ public abstract class AxisTracing implements ICollide, ISetMargins {
|
|||
if (step > maxSteps) {
|
||||
return;
|
||||
}
|
||||
final boolean checkInitiallyColliding = ignoreInitiallyColliding && !ignoredBlocks.isEmpty();
|
||||
final boolean checkInitiallyColliding = shouldCheckForIgnoredBlocks();
|
||||
for (int x = iMinX; x <= iMaxX; x++) {
|
||||
for (int z = iMinZ; z <= iMaxZ; z++) {
|
||||
if (checkInitiallyColliding && ignoredBlocks.containsBlockPosition(x, y, z)) {
|
||||
if (checkInitiallyColliding && isBlockIgnored(x, y, z)) {
|
||||
// Ignore.
|
||||
}
|
||||
else if (!step(x, y, z, xMin, increment == 1 ? yStart : yEnd, zMin, xMax, increment == 1 ? yEnd : yStart, zMax, Axis.Y_AXIS, increment)) {
|
||||
|
@ -272,10 +279,10 @@ public abstract class AxisTracing implements ICollide, ISetMargins {
|
|||
if (step > maxSteps) {
|
||||
return;
|
||||
}
|
||||
final boolean checkInitiallyColliding = ignoreInitiallyColliding && !ignoredBlocks.isEmpty();
|
||||
final boolean checkInitiallyColliding = shouldCheckForIgnoredBlocks();
|
||||
for (int y = iMinY; y <= iMaxY; y++) {
|
||||
for (int z = iMinZ; z <= iMaxZ; z++) {
|
||||
if (checkInitiallyColliding && ignoredBlocks.containsBlockPosition(x, y, z)) {
|
||||
if (checkInitiallyColliding && isBlockIgnored(x, y, z)) {
|
||||
// Ignore.
|
||||
}
|
||||
else if (!step(x, y, z, increment == 1 ? xStart : xEnd, yMin, zMin, increment == 1 ? xEnd : xStart, yMax, zMax, Axis.X_AXIS, increment)) {
|
||||
|
@ -320,7 +327,7 @@ public abstract class AxisTracing implements ICollide, ISetMargins {
|
|||
final int iMaxX = Location.locToBlock(xMax);
|
||||
final int iStartZ = Location.locToBlock(zStart);
|
||||
axisStep = 0;
|
||||
final boolean checkInitiallyColliding = ignoreInitiallyColliding && !ignoredBlocks.isEmpty();
|
||||
final boolean checkInitiallyColliding = shouldCheckForIgnoredBlocks();
|
||||
for (int z = iStartZ; z != iEndZ; z += increment) {
|
||||
++step;
|
||||
++axisStep;
|
||||
|
@ -329,7 +336,7 @@ public abstract class AxisTracing implements ICollide, ISetMargins {
|
|||
}
|
||||
for (int y = iMinY; y <= iMaxY; y++) {
|
||||
for (int x = iMinX; x <= iMaxX; x++) {
|
||||
if (checkInitiallyColliding && ignoredBlocks.containsBlockPosition(x, y, z)) {
|
||||
if (checkInitiallyColliding && isBlockIgnored(x, y, z)) {
|
||||
// Ignore.
|
||||
}
|
||||
else if (!step(x, y, z, xMin, yMin, increment == 1 ? zStart : zEnd, xMax, yMax, increment == 1 ? zEnd : zStart, Axis.Z_AXIS, increment)) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user