Implement ignoreInitiallyColliding for (Passable) AxisTracing.

Not really adding general purpose implementations for
BlockPositionContainer, likely good enough for what we need for the time
being.
This commit is contained in:
asofold 2016-06-11 13:49:46 +02:00
parent 64dedf3434
commit ec333fb432
8 changed files with 254 additions and 24 deletions

View File

@ -0,0 +1,38 @@
package fr.neatmonster.nocheatplus.components.location;
/**
* Simple immutable block position.
*
* @author asofold
*
*/
public class BlockPositionGet implements IGetBlockPosition {
private final int x;
private final int y;
private final int z;
public BlockPositionGet(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
@Override
public int getBlockX() {
return x;
}
@Override
public int getBlockY() {
return y;
}
@Override
public int getBlockZ() {
return z;
}
// TODO: equals vs. IGetBlockPosition, Coord(Hash)Map compatible hashCode.
}

View File

@ -0,0 +1,14 @@
package fr.neatmonster.nocheatplus.components.location;
/**
* Minimal interface for adding block positions.
*
* @author asofold
*
*/
public interface IAddBlockPosition {
/** Add block coordinates. */
public void addBlockPosition(int x, int y, int z);
}

View File

@ -0,0 +1,15 @@
package fr.neatmonster.nocheatplus.components.location;
/**
* Minimal interface for checking if a block positions is contained.
*
* @author asofold
*
*/
public interface IContainBlockPosition {
public boolean containsBlockPosition(int x, int y, int z);
public boolean containsBlockPosition(IGetBlockPosition blockPosition);
}

View File

@ -48,6 +48,7 @@ import fr.neatmonster.nocheatplus.config.WorldConfigProvider;
import fr.neatmonster.nocheatplus.logging.LogManager;
import fr.neatmonster.nocheatplus.logging.StaticLog;
import fr.neatmonster.nocheatplus.logging.Streams;
import fr.neatmonster.nocheatplus.utilities.collision.BlockPositionContainer;
import fr.neatmonster.nocheatplus.utilities.collision.ICollidePassable;
import fr.neatmonster.nocheatplus.utilities.collision.PassableAxisTracing;
import fr.neatmonster.nocheatplus.utilities.collision.PassableRayTracing;
@ -3153,6 +3154,43 @@ public class BlockProperties {
return false;
}
/**
* Add the block coordinates that are colliding via a isPassableBox check
* for the given bounds to the given container.
*
* @param access
* @param minX
* @param minY
* @param minZ
* @param maxX
* @param maxY
* @param maxZ
* @param results
*/
public static final int collectInitiallyCollidingBlocks(final BlockCache access,
final double minX, final double minY, final double minZ,
final double maxX, final double maxY, final double maxZ,
final BlockPositionContainer results) {
int added = 0;
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)) {
results.addBlockPosition(x, y, z);
++added;
}
}
}
}
return added;
}
/**
* Test for special case activation: trap door is climbable above ladder
* with distinct facing.

View File

@ -34,6 +34,11 @@ public abstract class AxisTracing implements ICollide, ISetMargins {
*/
private boolean cutOppositeDirectionMargin = false;
private boolean ignoreInitiallyColliding = false;
/** Blocks that are to be ignored. */
private final BlockPositionContainer ignoredBlocks = new BlockPositionContainer();
/** Result returned with collides() and reset to false on set/loop. */
protected boolean collides;
@ -77,6 +82,16 @@ public abstract class AxisTracing implements ICollide, ISetMargins {
return axisStep;
}
@Override
public void setIgnoreInitiallyColliding(boolean ignoreInitiallyColliding) {
this.ignoreInitiallyColliding = ignoreInitiallyColliding;
}
@Override
public boolean getIgnoreInitiallyColliding() {
return ignoreInitiallyColliding;
}
/**
* Indicate if a collision appeared during loop().
* @return
@ -131,7 +146,10 @@ public abstract class AxisTracing implements ICollide, ISetMargins {
double x = this.x0;
double y = this.y0;
double z = this.z0;
// TODO: if (ignoreInitiallyColliding) -> fetch blocks, test in runAxis.
if (ignoreInitiallyColliding) {
collectInitiallyCollidingBlocks(x0 - marginXneg, y0 - marginYneg, z0 - marginZneg,
x0 + marginXpos, y0 + marginYpos, z0 + marginZpos, ignoredBlocks);
}
for (int i = 0; i < 3; i++) {
final Axis axis = axisOrder[i];
collidesAxis = axis; // Ensure here, to get it on max steps.
@ -157,6 +175,9 @@ public abstract class AxisTracing implements ICollide, ISetMargins {
break;
}
}
if (ignoreInitiallyColliding) {
ignoredBlocks.clear();
}
}
@ -197,10 +218,13 @@ public abstract class AxisTracing implements ICollide, ISetMargins {
if (step > maxSteps) {
return;
}
// TODO: Ignore first setting?
final boolean checkInitiallyColliding = ignoreInitiallyColliding && !ignoredBlocks.isEmpty();
for (int x = iMinX; x <= iMaxX; x++) {
for (int z = iMinZ; z <= iMaxZ; z++) {
if (!step(x, y, z, xMin, increment == 1 ? yStart : yEnd, zMin, xMax, increment == 1 ? yEnd : yStart, zMax, Axis.Y_AXIS, increment)) {
if (checkInitiallyColliding && ignoredBlocks.containsBlockPosition(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)) {
collides = true;
return;
}
@ -248,10 +272,13 @@ public abstract class AxisTracing implements ICollide, ISetMargins {
if (step > maxSteps) {
return;
}
// TODO: Ignore first setting?
final boolean checkInitiallyColliding = ignoreInitiallyColliding && !ignoredBlocks.isEmpty();
for (int y = iMinY; y <= iMaxY; y++) {
for (int z = iMinZ; z <= iMaxZ; z++) {
if (!step(x, y, z, increment == 1 ? xStart : xEnd, yMin, zMin, increment == 1 ? xEnd : xStart, yMax, zMax, Axis.X_AXIS, increment)) {
if (checkInitiallyColliding && ignoredBlocks.containsBlockPosition(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)) {
collides = true;
return;
}
@ -293,16 +320,19 @@ 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();
for (int z = iStartZ; z != iEndZ; z += increment) {
++step;
++axisStep;
if (step > maxSteps) {
return;
}
// TODO: Ignore first setting?
for (int y = iMinY; y <= iMaxY; y++) {
for (int x = iMinX; x <= iMaxX; x++) {
if (!step(x, y, z, xMin, yMin, increment == 1 ? zStart : zEnd, xMax, yMax, increment == 1 ? zEnd : zStart, Axis.Z_AXIS, increment)) {
if (checkInitiallyColliding && ignoredBlocks.containsBlockPosition(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)) {
collides = true;
return;
}
@ -313,6 +343,23 @@ public abstract class AxisTracing implements ICollide, ISetMargins {
return;
}
/**
* In case ignoreInitiallyColliding is set, this will be called to do the
* actual collision checking with the given initial margins.
*
* @param minX
* @param minY
* @param minZ
* @param maxX
* @param maxY
* @param maxZ
* @param results
*/
protected abstract void collectInitiallyCollidingBlocks(
final double minX, final double minY, final double minZ,
final double maxX, final double maxY, final double maxZ,
final BlockPositionContainer results);
/**
* Check a block position for collision with the ordered bounds of a move
* along one axis.

View File

@ -0,0 +1,87 @@
package fr.neatmonster.nocheatplus.utilities.collision;
import java.util.LinkedList;
import fr.neatmonster.nocheatplus.components.location.BlockPositionGet;
import fr.neatmonster.nocheatplus.components.location.IAddBlockPosition;
import fr.neatmonster.nocheatplus.components.location.IContainBlockPosition;
import fr.neatmonster.nocheatplus.components.location.IGetBlockPosition;
/**
* A kept-simple container for block positions, meant to provide fast adding and
* fast contains checks (and fast clear). Intended use is to add blocks first,
* then query if blocks are contained with advancing coordinates like with
* ray-tracing or axis-tracing. Currently adding blocks twice is not meant to
* happen, and we assume blocks to be few.
*
* @author asofold
*
*/
public class BlockPositionContainer implements IAddBlockPosition, IContainBlockPosition {
// TODO: Not sure where to put this.
// TODO: Future use / interfacing could involve collecting cuboids from block positions (mining/activity/areas).
// TODO: Consider switching to HashSet or CoordMap.
private final LinkedList<BlockPositionGet> blocks = new LinkedList<BlockPositionGet>();
private int minX, minY, minZ, maxX, maxY, maxZ;
public BlockPositionContainer() {
resetBoundaries();
}
private void resetBoundaries() {
minX = Integer.MAX_VALUE;
minY = Integer.MAX_VALUE;
minZ = Integer.MAX_VALUE;
maxX = Integer.MIN_VALUE;
maxY = Integer.MIN_VALUE;
maxZ = Integer.MIN_VALUE;
}
private void fitBoundaries(final int x, final int y, final int z) {
minX = Math.min(x, minX);
minY = Math.min(y, minY);
minZ = Math.min(z, minZ);
maxX = Math.max(x, maxX);
maxY = Math.max(y, maxY);
maxZ = Math.max(z, maxZ);
}
@Override
public void addBlockPosition(final int x, final int y, final int z) {
fitBoundaries(x, y, z);
blocks.add(new BlockPositionGet(x, y, z));
}
@Override
public boolean containsBlockPosition(final int x, final int y, final int z) {
if (x < minX || y < minY || z < minZ || x > maxX || y > maxY || z > maxZ) {
return false;
}
for (final BlockPositionGet pos : blocks) {
if (x == pos.getBlockX() && z == pos.getBlockZ() && y == pos.getBlockY()) {
return true;
}
}
return false;
}
@Override
public boolean containsBlockPosition(final IGetBlockPosition blockPosition) {
return containsBlockPosition(blockPosition.getBlockX(), blockPosition.getBlockY(), blockPosition.getBlockZ());
}
public boolean isEmpty() {
return blocks.isEmpty();
}
public void clear() {
if (!isEmpty()) {
resetBoundaries();
blocks.clear();
}
}
}

View File

@ -24,7 +24,8 @@ public interface ICollide {
/**
* Call before loop, in order to skip checking blocks that are found to be
* colliding at the start of loop. May or may not have any effect.
* colliding at the start of loop. May or may not have any effect. This must
* not be called during processing of loop.
*
* @param ignoreInitiallyColliding
*/

View File

@ -8,8 +8,6 @@ public class PassableAxisTracing extends AxisTracing implements ICollidePassable
private BlockCache blockCache;
private boolean ignoreInitiallyColliding = false;
// TODO: Might need another option for margins (option to skip margin for the axis-start point, or alter ignoreFirst behavior).
// TODO: Consider an iteration margin as well (0.5 below for fences).
@ -21,15 +19,17 @@ public class PassableAxisTracing extends AxisTracing implements ICollidePassable
this.blockCache = blockCache;
}
@Override
protected void collectInitiallyCollidingBlocks(double minX, double minY, double minZ, double maxX, double maxY,
double maxZ, BlockPositionContainer results) {
BlockProperties.collectInitiallyCollidingBlocks(blockCache, minX, minY, minZ, maxX, maxY, maxZ, results);
}
@Override
protected boolean step(final int blockX, final int blockY, final int blockZ,
final double minX, final double minY, final double minZ,
final double maxX, final double maxY, final double maxZ,
final Axis axis, final int increment) {
// TODO: Ignore blocks by coordinates (handle before calling step).
if (ignoreInitiallyColliding && step == 1) {
return true;
}
if (BlockProperties.isPassableBox(blockCache, blockX, blockY, blockZ, minX, minY, minZ, maxX, maxY, maxZ)) {
return true;
}
@ -50,16 +50,6 @@ public class PassableAxisTracing extends AxisTracing implements ICollidePassable
setBlockCache(from.getBlockCache());
}
@Override
public void setIgnoreInitiallyColliding(boolean ignoreInitiallyColliding) {
this.ignoreInitiallyColliding = ignoreInitiallyColliding;
}
@Override
public boolean getIgnoreInitiallyColliding() {
return ignoreInitiallyColliding;
}
@Override
public boolean mightNeedSplitAxisHandling() {
return false;