/*
* This file is part of LanternServer, licensed under the MIT License (MIT).
*
* Copyright (c) LanternPowered <https://www.lanternpowered.org>
* Copyright (c) SpongePowered <https://www.spongepowered.org>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.lanternpowered.server.world.extent;
import com.flowpowered.math.vector.Vector3d;
import com.flowpowered.math.vector.Vector3i;
import org.lanternpowered.server.entity.LanternEntity;
import org.lanternpowered.server.util.VecHelper;
import org.spongepowered.api.block.BlockSnapshot;
import org.spongepowered.api.block.BlockState;
import org.spongepowered.api.block.BlockType;
import org.spongepowered.api.block.ScheduledBlockUpdate;
import org.spongepowered.api.block.tileentity.TileEntity;
import org.spongepowered.api.data.DataContainer;
import org.spongepowered.api.data.DataHolder;
import org.spongepowered.api.data.DataTransactionResult;
import org.spongepowered.api.data.DataView;
import org.spongepowered.api.data.Property;
import org.spongepowered.api.data.key.Key;
import org.spongepowered.api.data.manipulator.DataManipulator;
import org.spongepowered.api.data.merge.MergeFunction;
import org.spongepowered.api.data.persistence.InvalidDataException;
import org.spongepowered.api.data.value.BaseValue;
import org.spongepowered.api.data.value.immutable.ImmutableValue;
import org.spongepowered.api.entity.Entity;
import org.spongepowered.api.entity.EntitySnapshot;
import org.spongepowered.api.entity.EntityType;
import org.spongepowered.api.event.cause.Cause;
import org.spongepowered.api.item.inventory.ItemStack;
import org.spongepowered.api.util.AABB;
import org.spongepowered.api.util.Direction;
import org.spongepowered.api.util.Functional;
import org.spongepowered.api.util.PositionOutOfBoundsException;
import org.spongepowered.api.world.BlockChangeFlag;
import org.spongepowered.api.world.Location;
import org.spongepowered.api.world.World;
import org.spongepowered.api.world.biome.BiomeType;
import org.spongepowered.api.world.extent.ArchetypeVolume;
import org.spongepowered.api.world.extent.Extent;
import java.util.Collection;
import java.util.Iterator;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.function.Function;
import java.util.function.Predicate;
import javax.annotation.Nullable;
public class ExtentViewDownsize implements AbstractExtent {
private final Extent extent;
private final Vector3i blockMin;
private final Vector3i blockMax;
private final Vector3i blockSize;
private final Vector3i biomeMin;
private final Vector3i biomeMax;
private final Vector3i biomeSize;
public ExtentViewDownsize(Extent extent, Vector3i blockMin, Vector3i blockMax) {
this.extent = extent;
this.blockMin = blockMin;
this.blockMax = blockMax;
this.blockSize = this.blockMax.sub(this.blockMin).add(Vector3i.ONE);
this.biomeMin = new Vector3i(blockMin.getX(), 0, blockMin.getZ());
this.biomeMax = new Vector3i(blockMax.getX(), 1, blockMax.getZ());
this.biomeSize = this.biomeMax.sub(this.biomeMin).add(Vector3i.ONE.mul(1, 0, 1));
}
@Override
public Location<? extends Extent> getLocation(Vector3d position) {
this.checkRange(position.getX(), position.getY(), position.getZ());
return new Location<>(this, position);
}
@Override
public Location<? extends Extent> getLocation(Vector3i position) {
this.checkRange(position.getX(), position.getY(), position.getZ());
return new Location<>(this, position);
}
@Override
public UUID getUniqueId() {
return this.extent.getUniqueId();
}
@Override
public boolean isLoaded() {
return this.extent.isLoaded();
}
@Override
public Vector3i getBiomeMin() {
return this.biomeMin;
}
@Override
public Vector3i getBiomeMax() {
return this.biomeMax;
}
@Override
public Vector3i getBiomeSize() {
return this.biomeSize;
}
@Override
public boolean containsBiome(int x, int y, int z) {
return VecHelper.inBounds(x, y, z, this.biomeMin, this.biomeMax);
}
private void checkBiomeRange(int x, int y, int z) {
if (!VecHelper.inBounds(x, y, z, this.biomeMin, this.biomeMax)) {
throw new PositionOutOfBoundsException(new Vector3i(x, y, z), this.biomeMin, this.biomeMax);
}
}
@Override
public boolean hitBlock(int x, int y, int z, Direction side, Cause cause) {
this.checkRange(x, y, z);
return this.extent.hitBlock(x, y, z, side, cause);
}
@Override
public boolean interactBlock(int x, int y, int z, Direction side, Cause cause) {
this.checkRange(x, y, z);
return this.extent.interactBlock(x, y, z, side, cause);
}
@Override
public boolean interactBlockWith(int x, int y, int z, ItemStack itemStack, Direction side, Cause cause) {
this.checkRange(x, y, z);
return this.extent.interactBlockWith(x, y, z, itemStack, side, cause);
}
@Override
public boolean placeBlock(int x, int y, int z, BlockState block, Direction direction, Cause cause) {
this.checkRange(x, y, z);
return this.extent.placeBlock(x, y, z, block, direction, cause);
}
@Override
public boolean digBlock(int x, int y, int z, Cause cause) {
this.checkRange(x, y, z);
return this.extent.digBlock(x, y, z, cause);
}
@Override
public boolean digBlockWith(int x, int y, int z, ItemStack itemStack, Cause cause) {
this.checkRange(x, y, z);
return this.extent.digBlockWith(x, y, z, itemStack, cause);
}
@Override
public int getBlockDigTimeWith(int x, int y, int z, ItemStack itemStack, Cause cause) {
this.checkRange(x, y, z);
return this.extent.getBlockDigTimeWith(x, y, z, itemStack, cause);
}
@Override
public BiomeType getBiome(int x, int y, int z) {
this.checkBiomeRange(x, y, z);
return this.extent.getBiome(x, y, z);
}
@Override
public void setBiome(int x, int y, int z, BiomeType biome) {
this.checkBiomeRange(x, y, z);
this.extent.setBiome(x, y, z, biome);
}
@Override
public Vector3i getBlockMax() {
return this.blockMax;
}
@Override
public Vector3i getBlockMin() {
return this.blockMin;
}
@Override
public Vector3i getBlockSize() {
return this.blockSize;
}
@Override
public boolean containsBlock(int x, int y, int z) {
return VecHelper.inBounds(x, y, z, this.blockMin, this.blockMax);
}
private void checkRange(double x, double y, double z) {
if (!VecHelper.inBounds(x, y, z, this.blockMin, this.blockMax)) {
throw new PositionOutOfBoundsException(new Vector3d(x, y, z), this.blockMin.toDouble(), this.blockMax.toDouble());
}
}
private void checkRange(int x, int y, int z) {
if (!VecHelper.inBounds(x, y, z, this.blockMin, this.blockMax)) {
throw new PositionOutOfBoundsException(new Vector3i(x, y, z), this.blockMin, this.blockMax);
}
}
@Override
public BlockType getBlockType(int x, int y, int z) {
return this.getBlock(x, y, z).getType();
}
@Override
public BlockState getBlock(int x, int y, int z) {
this.checkRange(x, y, z);
return this.extent.getBlock(x, y, z);
}
@Override
public <T extends Property<?, ?>> Optional<T> getProperty(int x, int y, int z, Direction direction, Class<T> propertyClass) {
this.checkRange(x, y, z);
return this.extent.getProperty(x, y, z, direction, propertyClass);
}
@Override
public Collection<Direction> getFacesWithProperty(int x, int y, int z, Class<? extends Property<?, ?>> propertyClass) {
this.checkRange(x, y, z);
return this.extent.getFacesWithProperty(x, y, z, propertyClass);
}
@Override
public boolean setBlock(int x, int y, int z, BlockState block, BlockChangeFlag flag, Cause cause) {
this.checkRange(x, y, z);
return this.extent.setBlock(x, y, z, block, flag, cause);
}
@Override
public boolean setBlock(int x, int y, int z, BlockState blockState, Cause cause) {
this.checkRange(x, y, z);
return this.extent.setBlock(x, y, z, blockState, cause);
}
@Override
public BlockSnapshot createSnapshot(int x, int y, int z) {
this.checkRange(x, y, z);
return this.extent.createSnapshot(x, y, z);
}
@Override
public boolean restoreSnapshot(int x, int y, int z, BlockSnapshot snapshot, boolean force,
BlockChangeFlag flag, Cause cause) {
this.checkRange(x, y, z);
return this.extent.restoreSnapshot(x, y, z, snapshot, force, flag, cause);
}
@Override
public Optional<Entity> restoreSnapshot(EntitySnapshot snapshot, Vector3d position) {
this.checkRange(position.getX(), position.getY(), position.getZ());
return this.extent.restoreSnapshot(snapshot, position);
}
@Override
public boolean spawnEntity(Entity entity, Cause cause) {
final Vector3d pos = entity.getLocation().getPosition();
this.checkRange(pos.getX(), pos.getY(), pos.getZ());
return this.extent.spawnEntity(entity, cause);
}
@Override
public boolean spawnEntities(Iterable<? extends Entity> entities, Cause cause) {
for (Entity entity : entities) {
final Vector3d pos = entity.getLocation().getPosition();
this.checkRange(pos.getX(), pos.getY(), pos.getZ());
}
return this.extent.spawnEntities(entities, cause);
}
@Override
public Set<Entity> getIntersectingEntities(AABB box, Predicate<Entity> filter) {
this.checkRange(box.getMin().getX(), box.getMin().getY(), box.getMin().getZ());
this.checkRange(box.getMax().getX(), box.getMax().getY(), box.getMax().getZ());
return this.extent.getIntersectingEntities(box, filter);
}
@Override
public Set<EntityHit> getIntersectingEntities(Vector3d start, Vector3d direction, double distance, Predicate<EntityHit> filter) {
// Order matters! Bounds filter before the argument filter so it doesn't see out of bounds entities
final Vector3i max = this.blockMax.add(Vector3i.ONE);
return this.extent.getIntersectingEntities(start, direction, distance,
Functional.predicateAnd(hit -> VecHelper.inBounds(hit.getEntity().getLocation().getPosition(), this.blockMin, max), filter));
}
@Override
public Set<EntityHit> getIntersectingEntities(Vector3d start, Vector3d end, Predicate<EntityHit> filter) {
// Order matters! Bounds filter before the argument filter so it doesn't see out of bounds entities
final Vector3i max = this.blockMax.add(Vector3i.ONE);
return this.extent.getIntersectingEntities(start, end,
Functional.predicateAnd(hit -> VecHelper.inBounds(hit.getEntity().getLocation().getPosition(), this.blockMin, max), filter));
}
@Override
public Collection<ScheduledBlockUpdate> getScheduledUpdates(int x, int y, int z) {
this.checkRange(x, y, z);
return this.extent.getScheduledUpdates(x, y, z);
}
@Override
public ScheduledBlockUpdate addScheduledUpdate(int x, int y, int z, int priority, int ticks) {
this.checkRange(x, y, z);
return this.extent.addScheduledUpdate(x, y, z, priority, ticks);
}
@Override
public void removeScheduledUpdate(int x, int y, int z, ScheduledBlockUpdate update) {
this.checkRange(x, y, z);
this.extent.removeScheduledUpdate(x, y, z, update);
}
@Override
public <T extends Property<?, ?>> Optional<T> getProperty(int x, int y, int z, Class<T> propertyClass) {
this.checkRange(x, y, z);
return this.extent.getProperty(x, y, z, propertyClass);
}
@Override
public Collection<Property<?, ?>> getProperties(int x, int y, int z) {
this.checkRange(x, y, z);
return this.extent.getProperties(x, y, z);
}
@Override
public <E> Optional<E> get(int x, int y, int z, Key<? extends BaseValue<E>> key) {
this.checkRange(x, y, z);
return this.extent.get(x, y, z, key);
}
@Override
public <T extends DataManipulator<?, ?>> Optional<T> get(int x, int y, int z, Class<T> manipulatorClass) {
this.checkRange(x, y, z);
return this.extent.get(x, y, z, manipulatorClass);
}
@Override
public Set<ImmutableValue<?>> getValues(int x, int y, int z) {
this.checkRange(x, y, z);
return this.extent.getValues(x, y, z);
}
@Override
public <T extends DataManipulator<?, ?>> Optional<T> getOrCreate(int x, int y, int z, Class<T> manipulatorClass) {
this.checkRange(x, y, z);
return this.extent.getOrCreate(x, y, z, manipulatorClass);
}
@Override
public <E> E getOrNull(int x, int y, int z, Key<? extends BaseValue<E>> key) {
this.checkRange(x, y, z);
return this.extent.getOrNull(x, y, z, key);
}
@Override
public <E> E getOrElse(int x, int y, int z, Key<? extends BaseValue<E>> key, E defaultValue) {
this.checkRange(x, y, z);
return this.extent.getOrElse(x, y, z, key, defaultValue);
}
@Override
public <E, V extends BaseValue<E>> Optional<V> getValue(int x, int y, int z, Key<V> key) {
this.checkRange(x, y, z);
return this.extent.getValue(x, y, z, key);
}
@Override
public boolean supports(int x, int y, int z, Key<?> key) {
this.checkRange(x, y, z);
return this.extent.supports(x, y, z, key);
}
@Override
public boolean supports(int x, int y, int z, BaseValue<?> value) {
this.checkRange(x, y, z);
return this.extent.supports(x, y, z, value);
}
@Override
public boolean supports(int x, int y, int z, Class<? extends DataManipulator<?, ?>> manipulatorClass) {
this.checkRange(x, y, z);
return this.extent.supports(x, y, z, manipulatorClass);
}
@Override
public boolean supports(int x, int y, int z, DataManipulator<?, ?> manipulator) {
this.checkRange(x, y, z);
return this.extent.supports(x, y, z, manipulator);
}
@Override
public Set<Key<?>> getKeys(int x, int y, int z) {
this.checkRange(x, y, z);
return this.extent.getKeys(x, y, z);
}
@Override
public <E> DataTransactionResult transform(int x, int y, int z, Key<? extends BaseValue<E>> key, Function<E, E> function) {
this.checkRange(x, y, z);
return this.extent.transform(x, y, z, key, function);
}
@Override
public <E> DataTransactionResult offer(int x, int y, int z, BaseValue<E> value) {
this.checkRange(x, y, z);
return this.extent.offer(x, y, z, value);
}
@Override
public <E> DataTransactionResult offer(int x, int y, int z, Key<? extends BaseValue<E>> key, E value) {
this.checkRange(x, y, z);
return this.extent.offer(x, y, z, key, value);
}
@Override
public <E> DataTransactionResult offer(int x, int y, int z, Key<? extends BaseValue<E>> key, E value, Cause cause) {
this.checkRange(x, y, z);
return this.extent.offer(x, y, z, key, value, cause);
}
@Override
public DataTransactionResult offer(int x, int y, int z, DataManipulator<?, ?> manipulator) {
this.checkRange(x, y, z);
return this.extent.offer(x, y, z, manipulator);
}
@Override
public DataTransactionResult offer(int x, int y, int z, DataManipulator<?, ?> manipulator, MergeFunction function) {
this.checkRange(x, y, z);
return this.extent.offer(x, y, z, manipulator, function);
}
@Override
public DataTransactionResult offer(int x, int y, int z, DataManipulator<?, ?> manipulator, MergeFunction function, Cause cause) {
this.checkRange(x, y, z);
return this.extent.offer(x, y, z, manipulator, function, cause);
}
@Override
public DataTransactionResult offer(int x, int y, int z, Iterable<DataManipulator<?, ?>> manipulators) {
this.checkRange(x, y, z);
return this.extent.offer(x, y, z, manipulators);
}
@Override
public DataTransactionResult offer(Vector3i blockPosition, Iterable<DataManipulator<?, ?>> values, MergeFunction function) {
this.checkRange(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ());
return this.extent.offer(blockPosition, values, function);
}
@Override
public DataTransactionResult remove(int x, int y, int z, Key<?> key) {
this.checkRange(x, y, z);
return this.extent.remove(x, y, z, key);
}
@Override
public DataTransactionResult remove(int x, int y, int z, Class<? extends DataManipulator<?, ?>> manipulatorClass) {
this.checkRange(x, y, z);
return this.extent.remove(x, y, z, manipulatorClass);
}
@Override
public DataTransactionResult undo(int x, int y, int z, DataTransactionResult result) {
this.checkRange(x, y, z);
return this.extent.undo(x, y, z, result);
}
@Override
public Collection<DataManipulator<?, ?>> getManipulators(int x, int y, int z) {
this.checkRange(x, y, z);
return this.extent.getManipulators(x, y, z);
}
@Override
public boolean validateRawData(int x, int y, int z, DataView container) {
this.checkRange(x, y, z);
return this.extent.validateRawData(x, y, z, container);
}
@Override
public void setRawData(int x, int y, int z, DataView container) throws InvalidDataException {
this.checkRange(x, y, z);
this.extent.setRawData(x, y, z, container);
}
@Override
public DataTransactionResult copyFrom(int xTo, int yTo, int zTo, DataHolder from) {
this.checkRange(xTo, yTo, zTo);
return this.extent.copyFrom(xTo, yTo, zTo, from);
}
@Override
public DataTransactionResult copyFrom(int xTo, int yTo, int zTo, int xFrom, int yFrom, int zFrom) {
this.checkRange(xTo, yTo, zTo);
this.checkRange(xFrom, yFrom, zFrom);
return this.extent.copyFrom(xTo, yTo, zTo, xFrom, yFrom, zFrom);
}
@Override
public DataTransactionResult copyFrom(int xTo, int yTo, int zTo, DataHolder from, MergeFunction function) {
this.checkRange(xTo, yTo, zTo);
return this.extent.copyFrom(xTo, yTo, zTo, from, function);
}
@Override
public DataTransactionResult copyFrom(int xTo, int yTo, int zTo, int xFrom, int yFrom, int zFrom, MergeFunction function) {
this.checkRange(xTo, yTo, zTo);
this.checkRange(xFrom, yFrom, zFrom);
return this.extent.copyFrom(xTo, yTo, zTo, xFrom, yFrom, zFrom, function);
}
@Override
public Collection<TileEntity> getTileEntities() {
final Collection<TileEntity> tileEntities = this.extent.getTileEntities();
for (Iterator<TileEntity> iterator = tileEntities.iterator(); iterator.hasNext(); ) {
final TileEntity tileEntity = iterator.next();
final Location<World> block = tileEntity.getLocation();
if (!VecHelper.inBounds(block.getX(), block.getY(), block.getZ(), this.blockMin, this.blockMax)) {
iterator.remove();
}
}
return tileEntities;
}
@Override
public Collection<TileEntity> getTileEntities(Predicate<TileEntity> filter) {
// Order matters! Bounds filter before the argument filter so it doesn't see out of bounds entities
return this.extent.getTileEntities(Functional.predicateAnd(
new TileEntityInBounds(this.blockMin, this.blockMax), filter));
}
@Override
public Optional<TileEntity> getTileEntity(int x, int y, int z) {
this.checkRange(x, y, z);
return this.extent.getTileEntity(x, y, z);
}
@Override
public Entity createEntity(EntityType type, Vector3i position) {
this.checkRange(position.getX(), position.getY(), position.getZ());
return this.extent.createEntity(type, position);
}
@Override
public Optional<Entity> getEntity(UUID uuid) {
final Optional<Entity> optEntity = this.extent.getEntity(uuid);
if (optEntity.isPresent()) {
final Vector3d pos = ((LanternEntity) optEntity.get()).getPosition();
if (VecHelper.inBounds(pos.getFloorX(), pos.getFloorY(), pos.getFloorZ(), this.blockMin, this.blockMax)) {
return optEntity;
}
}
return Optional.empty();
}
@Override
public Collection<Entity> getEntities() {
final Collection<Entity> entities = this.extent.getEntities();
for (Iterator<Entity> iterator = entities.iterator(); iterator.hasNext(); ) {
final Entity entity = iterator.next();
final Vector3d pos = ((LanternEntity) entity).getPosition();
if (!VecHelper.inBounds(pos.getX(), pos.getY(), pos.getZ(), this.blockMin, this.blockMax)) {
iterator.remove();
}
}
return entities;
}
@Override
public Collection<Entity> getEntities(Predicate<Entity> filter) {
// Order matters! Bounds filter before the argument filter so it doesn't see out of bounds entities
return this.extent.getEntities(Functional.predicateAnd(input -> {
final Vector3d pos = ((LanternEntity) input).getPosition();
return VecHelper.inBounds(pos.getFloorX(), pos.getFloorY(), pos.getFloorZ(), this.blockMin, this.blockMax);
}, filter));
}
@Override
public Entity createEntity(EntityType type, Vector3d position) {
this.checkRange(position.getX(), position.getY(), position.getZ());
return this.extent.createEntity(type, position);
}
@Override
public Optional<Entity> createEntity(DataContainer entityContainer) {
// TODO once entity containers are implemented
// checkRange(position.getX(), position.getY(), position.getZ());
return Optional.empty();
}
@Override
public Optional<Entity> createEntity(DataContainer entityContainer, Vector3d position) {
this.checkRange(position.getX(), position.getY(), position.getZ());
return this.extent.createEntity(entityContainer, position);
}
@Override
public Extent getExtentView(Vector3i newMin, Vector3i newMax) {
this.checkRange(newMin.getX(), newMin.getY(), newMin.getZ());
this.checkRange(newMax.getX(), newMax.getY(), newMax.getZ());
return new ExtentViewDownsize(this.extent, newMin, newMax);
}
@Override
public Optional<UUID> getCreator(int x, int y, int z) {
this.checkRange(x, y, z);
return this.extent.getCreator(x, y, z);
}
@Override
public Optional<UUID> getNotifier(int x, int y, int z) {
this.checkRange(x, y, z);
return this.extent.getNotifier(x, y, z);
}
@Override
public void setCreator(int x, int y, int z, @Nullable UUID uuid) {
this.checkRange(x, y, z);
this.extent.setCreator(x, y, z, uuid);
}
@Override
public void setNotifier(int x, int y, int z, @Nullable UUID uuid) {
this.checkRange(x, y, z);
this.extent.setNotifier(x, y, z, uuid);
}
@Override
public Optional<AABB> getBlockSelectionBox(int x, int y, int z) {
this.checkRange(x, y, z);
return this.extent.getBlockSelectionBox(x, y, z);
}
@Override
public Set<AABB> getIntersectingBlockCollisionBoxes(AABB box) {
this.checkRange(box.getMin().getX(), box.getMin().getY(), box.getMin().getZ());
this.checkRange(box.getMax().getX(), box.getMax().getY(), box.getMax().getZ());
return this.extent.getIntersectingBlockCollisionBoxes(box);
}
@Override
public Set<AABB> getIntersectingCollisionBoxes(Entity owner, AABB box) {
this.checkRange(box.getMin().getX(), box.getMin().getY(), box.getMin().getZ());
this.checkRange(box.getMax().getX(), box.getMax().getY(), box.getMax().getZ());
return this.extent.getIntersectingCollisionBoxes(owner, box);
}
@Override
public ArchetypeVolume createArchetypeVolume(Vector3i min, Vector3i max, Vector3i origin) {
this.checkRange(min.getX(), min.getY(), min.getZ());
this.checkRange(max.getX(), max.getY(), max.getZ());
return this.extent.createArchetypeVolume(min, max, origin);
}
private static class TileEntityInBounds implements Predicate<TileEntity> {
private final Vector3i min;
private final Vector3i max;
private TileEntityInBounds(Vector3i min, Vector3i max) {
this.min = min;
this.max = max;
}
@Override
public boolean test(TileEntity input) {
final Location<World> block = input.getLocation();
return VecHelper.inBounds(block.getX(), block.getY(), block.getZ(), this.min, this.max);
}
}
}