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 baritone.api.cache.IWorldData;
021import net.minecraft.block.BlockSlab;
022import net.minecraft.client.entity.EntityPlayerSP;
023import net.minecraft.util.math.BlockPos;
024import net.minecraft.util.math.RayTraceResult;
025import net.minecraft.util.math.Vec3d;
026import net.minecraft.world.World;
027
028import java.util.Optional;
029
030/**
031 * @author Brady
032 * @since 11/12/2018
033 */
034public interface IPlayerContext {
035
036    EntityPlayerSP player();
037
038    IPlayerController playerController();
039
040    World world();
041
042    IWorldData worldData();
043
044    RayTraceResult objectMouseOver();
045
046    default BetterBlockPos playerFeet() {
047        // TODO find a better way to deal with soul sand!!!!!
048        BetterBlockPos feet = new BetterBlockPos(player().posX, player().posY + 0.1251, player().posZ);
049
050        // sometimes when calling this from another thread or while world is null, it'll throw a NullPointerException
051        // that causes the game to immediately crash
052        //
053        // so of course crashing on 2b is horribly bad due to queue times and logout spot
054        // catch the NPE and ignore it if it does happen
055        //
056        // this does not impact performance at all since we're not null checking constantly
057        // if there is an exception, the only overhead is Java generating the exception object... so we can ignore it
058        try {
059            if (world().getBlockState(feet).getBlock() instanceof BlockSlab) {
060                return feet.up();
061            }
062        } catch (NullPointerException ignored) {}
063
064        return feet;
065    }
066
067    default Vec3d playerFeetAsVec() {
068        return new Vec3d(player().posX, player().posY, player().posZ);
069    }
070
071    default Vec3d playerHead() {
072        return new Vec3d(player().posX, player().posY + player().getEyeHeight(), player().posZ);
073    }
074
075    default Rotation playerRotations() {
076        return new Rotation(player().rotationYaw, player().rotationPitch);
077    }
078
079    static double eyeHeight(boolean ifSneaking) {
080        return ifSneaking ? 1.54 : 1.62;
081    }
082
083    /**
084     * Returns the block that the crosshair is currently placed over. Updated once per tick.
085     *
086     * @return The position of the highlighted block
087     */
088    default Optional<BlockPos> getSelectedBlock() {
089        RayTraceResult result = objectMouseOver();
090        if (result != null && result.typeOfHit == RayTraceResult.Type.BLOCK) {
091            return Optional.of(result.getBlockPos());
092        }
093        return Optional.empty();
094    }
095
096    default boolean isLookingAt(BlockPos pos) {
097        return getSelectedBlock().equals(Optional.of(pos));
098    }
099}