/*
* This file is part of Skript.
*
* Skript is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Skript is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Skript. If not, see <http://www.gnu.org/licenses/>.
*
*
* Copyright 2011-2014 Peter Güttinger
*
*/
package ch.njol.skript.util;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.util.BlockIterator;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.Nullable;
import ch.njol.skript.Skript;
import ch.njol.util.Math2;
import ch.njol.util.NullableChecker;
import ch.njol.util.coll.iterator.StoppableIterator;
/**
* @author Peter Güttinger
*/
public class BlockLineIterator extends StoppableIterator<Block> {
/**
* @param start
* @param end
* @throws IllegalStateException randomly (Bukkit bug)
*/
@SuppressWarnings("null")
public BlockLineIterator(final Block start, final Block end) throws IllegalStateException {
super(new BlockIterator(start.getWorld(), fitInWorld(start.getLocation().add(0.5, 0.5, 0.5), end.getLocation().subtract(start.getLocation()).toVector()),
end.equals(start) ? new Vector(1, 0, 0) : end.getLocation().subtract(start.getLocation()).toVector(), 0, 0), // should prevent an error if start = end
new NullableChecker<Block>() {
private final double overshotSq = Math.pow(start.getLocation().distance(end.getLocation()) + 2, 2);
@Override
public boolean check(final @Nullable Block b) {
assert b != null;
if (b.getLocation().distanceSquared(start.getLocation()) > overshotSq)
throw new IllegalStateException("BlockLineIterator missed the end block!");
return b.equals(end);
}
}, true);
}
/**
* @param start
* @param dir
* @param dist
* @throws IllegalStateException randomly (Bukkit bug)
*/
public BlockLineIterator(final Location start, final Vector dir, final double dist) throws IllegalStateException {
super(new BlockIterator(start.getWorld(), fitInWorld(start, dir), dir, 0, 0), new NullableChecker<Block>() {
private final double distSq = dist * dist;
@Override
public boolean check(final @Nullable Block b) {
return b != null && b.getLocation().add(0.5, 0.5, 0.5).distanceSquared(start) >= distSq;
}
}, false);
}
/**
* @param start
* @param dir
* @param dist
* @throws IllegalStateException randomly (Bukkit bug)
*/
@SuppressWarnings("null")
public BlockLineIterator(final Block start, final Vector dir, final double dist) throws IllegalStateException {
this(start.getLocation().add(0.5, 0.5, 0.5), dir, dist);
}
@SuppressWarnings("null")
private final static Vector fitInWorld(final Location l, final Vector dir) {
if (0 <= l.getBlockY() && l.getBlockY() < l.getWorld().getMaxHeight())
return l.toVector();
final double y = Math2.fit(0, l.getY(), l.getWorld().getMaxHeight());
if (Math.abs(dir.getY()) < Skript.EPSILON)
return new Vector(l.getX(), y, l.getZ());
final double dy = y - l.getY();
final double n = dy / dir.getY();
return l.toVector().add(dir.clone().multiply(n));
}
}