cn.nukkit.utils.BlockIterator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of powernukkit Show documentation
Show all versions of powernukkit Show documentation
A Minecraft Bedrock Edition server software implementation made in Java from scratch which supports all new features.
package cn.nukkit.utils;
import cn.nukkit.block.Block;
import cn.nukkit.level.Level;
import cn.nukkit.math.BlockFace;
import cn.nukkit.math.Vector3;
import java.util.Iterator;
/**
* @author MagicDroidX (Nukkit Project)
*/
public class BlockIterator implements Iterator {
private final Level level;
private final int maxDistance;
private static final int gridSize = 1 << 24;
private boolean end = false;
private final Block[] blockQueue;
private int currentBlock = 0;
private Block currentBlockObject = null;
private int currentDistance;
private int maxDistanceInt = 0;
private int secondError;
private int thirdError;
private final int secondStep;
private final int thirdStep;
private BlockFace mainFace;
private BlockFace secondFace;
private BlockFace thirdFace;
public BlockIterator(Level level, Vector3 start, Vector3 direction) {
this(level, start, direction, 0);
}
public BlockIterator(Level level, Vector3 start, Vector3 direction, double yOffset) {
this(level, start, direction, yOffset, 0);
}
public BlockIterator(Level level, Vector3 start, Vector3 direction, double yOffset, int maxDistance) {
this.level = level;
this.maxDistance = maxDistance;
this.blockQueue = new Block[3];
Vector3 startClone = new Vector3(start.x, start.y, start.z);
startClone.y += yOffset;
this.currentDistance = 0;
double mainDirection = 0;
double secondDirection = 0;
double thirdDirection = 0;
double mainPosition = 0;
double secondPosition = 0;
double thirdPosition = 0;
Vector3 pos = new Vector3(startClone.x, startClone.y, startClone.z);
Block startBlock = this.level.getBlock(new Vector3(Math.floor(pos.x), Math.floor(pos.y), Math.floor(pos.z)));
if (this.getXLength(direction) > mainDirection) {
this.mainFace = this.getXFace(direction);
mainDirection = this.getXLength(direction);
mainPosition = this.getXPosition(direction, startClone, startBlock);
this.secondFace = this.getYFace(direction);
secondDirection = this.getYLength(direction);
secondPosition = this.getYPosition(direction, startClone, startBlock);
this.thirdFace = this.getZFace(direction);
thirdDirection = this.getZLength(direction);
thirdPosition = this.getZPosition(direction, startClone, startBlock);
}
if (this.getYLength(direction) > mainDirection) {
this.mainFace = this.getYFace(direction);
mainDirection = this.getYLength(direction);
mainPosition = this.getYPosition(direction, startClone, startBlock);
this.secondFace = this.getZFace(direction);
secondDirection = this.getZLength(direction);
secondPosition = this.getZPosition(direction, startClone, startBlock);
this.thirdFace = this.getXFace(direction);
thirdDirection = this.getXLength(direction);
thirdPosition = this.getXPosition(direction, startClone, startBlock);
}
if (this.getZLength(direction) > mainDirection) {
this.mainFace = this.getZFace(direction);
mainDirection = this.getZLength(direction);
mainPosition = this.getZPosition(direction, startClone, startBlock);
this.secondFace = this.getXFace(direction);
secondDirection = this.getXLength(direction);
secondPosition = this.getXPosition(direction, startClone, startBlock);
this.thirdFace = this.getYFace(direction);
thirdDirection = this.getYLength(direction);
thirdPosition = this.getYPosition(direction, startClone, startBlock);
}
double d = mainPosition / mainDirection;
double secondd = secondPosition - secondDirection * d;
double thirdd = thirdPosition - thirdDirection * d;
this.secondError = (int) Math.floor(secondd * gridSize);
this.secondStep = (int) Math.round(secondDirection / mainDirection * gridSize);
this.thirdError = (int) Math.floor(thirdd * gridSize);
this.thirdStep = (int) Math.round(thirdDirection / mainDirection * gridSize);
if (this.secondError + this.secondStep <= 0) {
this.secondError = -this.secondStep + 1;
}
if (this.thirdError + this.thirdStep <= 0) {
this.thirdError = -this.thirdStep + 1;
}
Block lastBlock = startBlock.getSide(this.mainFace.getOpposite());
if (this.secondError < 0) {
this.secondError += gridSize;
lastBlock = lastBlock.getSide(this.secondFace.getOpposite());
}
if (this.thirdError < 0) {
this.thirdError += gridSize;
lastBlock = lastBlock.getSide(this.thirdFace.getOpposite());
}
this.secondError -= gridSize;
this.thirdError -= gridSize;
this.blockQueue[0] = lastBlock;
this.currentBlock = -1;
this.scan();
boolean startBlockFound = false;
for (int cnt = this.currentBlock; cnt >= 0; --cnt) {
if (this.blockEquals(this.blockQueue[cnt], startBlock)) {
this.currentBlock = cnt;
startBlockFound = true;
break;
}
}
if (!startBlockFound) {
throw new IllegalStateException("Start block missed in BlockIterator");
}
this.maxDistanceInt = (int) Math.round(maxDistance / (Math.sqrt(mainDirection * mainDirection + secondDirection * secondDirection + thirdDirection * thirdDirection) / mainDirection));
}
private boolean blockEquals(Block a, Block b) {
return a.x == b.x && a.y == b.y && a.z == b.z;
}
private BlockFace getXFace(Vector3 direction) {
return ((direction.x) > 0) ? BlockFace.EAST : BlockFace.WEST;
}
private BlockFace getYFace(Vector3 direction) {
return ((direction.y) > 0) ? BlockFace.UP : BlockFace.DOWN;
}
private BlockFace getZFace(Vector3 direction) {
return ((direction.z) > 0) ? BlockFace.SOUTH : BlockFace.NORTH;
}
private double getXLength(Vector3 direction) {
return Math.abs(direction.x);
}
private double getYLength(Vector3 direction) {
return Math.abs(direction.y);
}
private double getZLength(Vector3 direction) {
return Math.abs(direction.z);
}
private double getPosition(double direction, double position, double blockPosition) {
return direction > 0 ? (position - blockPosition) : (blockPosition + 1 - position);
}
private double getXPosition(Vector3 direction, Vector3 position, Block block) {
return this.getPosition(direction.x, position.x, block.x);
}
private double getYPosition(Vector3 direction, Vector3 position, Block block) {
return this.getPosition(direction.y, position.y, block.y);
}
private double getZPosition(Vector3 direction, Vector3 position, Block block) {
return this.getPosition(direction.z, position.z, block.z);
}
@Override
public Block next() {
this.scan();
if (this.currentBlock <= -1) {
throw new IndexOutOfBoundsException();
} else {
this.currentBlockObject = this.blockQueue[this.currentBlock--];
}
return this.currentBlockObject;
}
@Override
public boolean hasNext() {
this.scan();
return this.currentBlock != -1;
}
private void scan() {
if (this.currentBlock >= 0) {
return;
}
if (this.maxDistance != 0 && this.currentDistance > this.maxDistanceInt) {
this.end = true;
return;
}
if (this.end) {
return;
}
++this.currentDistance;
this.secondError += this.secondStep;
this.thirdError += this.thirdStep;
if (this.secondError > 0 && this.thirdError > 0) {
this.blockQueue[2] = this.blockQueue[0].getSide(this.mainFace);
if ((this.secondStep * this.thirdError) < (this.thirdStep * this.secondError)) {
this.blockQueue[1] = this.blockQueue[2].getSide(this.secondFace);
this.blockQueue[0] = this.blockQueue[1].getSide(this.thirdFace);
} else {
this.blockQueue[1] = this.blockQueue[2].getSide(this.thirdFace);
this.blockQueue[0] = this.blockQueue[1].getSide(this.secondFace);
}
this.thirdError -= gridSize;
this.secondError -= gridSize;
this.currentBlock = 2;
} else if (this.secondError > 0) {
this.blockQueue[1] = this.blockQueue[0].getSide(this.mainFace);
this.blockQueue[0] = this.blockQueue[1].getSide(this.secondFace);
this.secondError -= gridSize;
this.currentBlock = 1;
} else if (this.thirdError > 0) {
this.blockQueue[1] = this.blockQueue[0].getSide(this.mainFace);
this.blockQueue[0] = this.blockQueue[1].getSide(this.thirdFace);
this.thirdError -= gridSize;
this.currentBlock = 1;
} else {
this.blockQueue[0] = this.blockQueue[0].getSide(this.mainFace);
this.currentBlock = 0;
}
}
}