001/*
002 * This file is part of Baritone.
003 *
004 * Baritone is free software: you can redistribute it and/or modify
005 * it under the terms of the GNU Lesser General Public License as published by
006 * the Free Software Foundation, either version 3 of the License, or
007 * (at your option) any later version.
008 *
009 * Baritone is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012 * GNU Lesser General Public License for more details.
013 *
014 * You should have received a copy of the GNU Lesser General Public License
015 * along with Baritone.  If not, see <https://www.gnu.org/licenses/>.
016 */
017
018package baritone.api.utils;
019
020import net.minecraft.core.BlockPos;
021import net.minecraft.core.Direction;
022import net.minecraft.world.entity.Entity;
023import net.minecraft.world.level.Level;
024import net.minecraft.world.level.block.BaseFireBlock;
025import net.minecraft.world.level.block.state.BlockState;
026import net.minecraft.world.phys.Vec3;
027import net.minecraft.world.phys.shapes.VoxelShape;
028
029/**
030 * @author Brady
031 * @since 10/13/2018
032 */
033public final class VecUtils {
034
035    private VecUtils() {}
036
037    /**
038     * Calculates the center of the block at the specified position's bounding box
039     *
040     * @param world The world that the block is in, used to provide the bounding box
041     * @param pos   The block position
042     * @return The center of the block's bounding box
043     * @see #getBlockPosCenter(BlockPos)
044     */
045    public static Vec3 calculateBlockCenter(Level world, BlockPos pos) {
046        BlockState b = world.getBlockState(pos);
047        VoxelShape shape = b.getCollisionShape(world, pos);
048        if (shape.isEmpty()) {
049            return getBlockPosCenter(pos);
050        }
051        double xDiff = (shape.min(Direction.Axis.X) + shape.max(Direction.Axis.X)) / 2;
052        double yDiff = (shape.min(Direction.Axis.Y) + shape.max(Direction.Axis.Y)) / 2;
053        double zDiff = (shape.min(Direction.Axis.Z) + shape.max(Direction.Axis.Z)) / 2;
054        if (Double.isNaN(xDiff) || Double.isNaN(yDiff) || Double.isNaN(zDiff)) {
055            throw new IllegalStateException(b + " " + pos + " " + shape);
056        }
057        if (b.getBlock() instanceof BaseFireBlock) {//look at bottom of fire when putting it out
058            yDiff = 0;
059        }
060        return new Vec3(
061                pos.getX() + xDiff,
062                pos.getY() + yDiff,
063                pos.getZ() + zDiff
064        );
065    }
066
067    /**
068     * Gets the assumed center position of the given block position.
069     * This is done by adding 0.5 to the X, Y, and Z axes.
070     * <p>
071     * TODO: We may want to consider replacing many usages of this method with #calculateBlockCenter(BlockPos)
072     *
073     * @param pos The block position
074     * @return The assumed center of the position
075     * @see #calculateBlockCenter(Level, BlockPos)
076     */
077    public static Vec3 getBlockPosCenter(BlockPos pos) {
078        return new Vec3(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5);
079    }
080
081    /**
082     * Gets the distance from the specified position to the assumed center of the specified block position.
083     *
084     * @param pos The block position
085     * @param x   The x pos
086     * @param y   The y pos
087     * @param z   The z pos
088     * @return The distance from the assumed block center to the position
089     * @see #getBlockPosCenter(BlockPos)
090     */
091    public static double distanceToCenter(BlockPos pos, double x, double y, double z) {
092        double xdiff = pos.getX() + 0.5 - x;
093        double ydiff = pos.getY() + 0.5 - y;
094        double zdiff = pos.getZ() + 0.5 - z;
095        return Math.sqrt(xdiff * xdiff + ydiff * ydiff + zdiff * zdiff);
096    }
097
098    /**
099     * Gets the distance from the specified entity's position to the assumed
100     * center of the specified block position.
101     *
102     * @param entity The entity
103     * @param pos    The block position
104     * @return The distance from the entity to the block's assumed center
105     * @see #getBlockPosCenter(BlockPos)
106     */
107    public static double entityDistanceToCenter(Entity entity, BlockPos pos) {
108        return distanceToCenter(pos, entity.position().x, entity.position().y, entity.position().z);
109    }
110
111    /**
112     * Gets the distance from the specified entity's position to the assumed
113     * center of the specified block position, ignoring the Y axis.
114     *
115     * @param entity The entity
116     * @param pos    The block position
117     * @return The horizontal distance from the entity to the block's assumed center
118     * @see #getBlockPosCenter(BlockPos)
119     */
120    public static double entityFlatDistanceToCenter(Entity entity, BlockPos pos) {
121        return distanceToCenter(pos, entity.position().x, pos.getY() + 0.5, entity.position().z);
122    }
123}