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.client.Minecraft;
022import net.minecraft.client.multiplayer.ClientLevel;
023import net.minecraft.client.player.LocalPlayer;
024import net.minecraft.core.BlockPos;
025import net.minecraft.world.entity.Entity;
026import net.minecraft.world.level.Level;
027import net.minecraft.world.level.block.SlabBlock;
028import net.minecraft.world.phys.BlockHitResult;
029import net.minecraft.world.phys.HitResult;
030import net.minecraft.world.phys.Vec3;
031
032import java.util.Optional;
033import java.util.stream.Stream;
034import java.util.stream.StreamSupport;
035
036/**
037 * @author Brady
038 * @since 11/12/2018
039 */
040public interface IPlayerContext {
041
042    Minecraft minecraft();
043
044    LocalPlayer player();
045
046    IPlayerController playerController();
047
048    Level world();
049
050    default Iterable<Entity> entities() {
051        return ((ClientLevel) world()).entitiesForRendering();
052    }
053
054    default Stream<Entity> entitiesStream() {
055        return StreamSupport.stream(entities().spliterator(), false);
056    }
057
058
059    IWorldData worldData();
060
061    HitResult objectMouseOver();
062
063    default BetterBlockPos playerFeet() {
064        // TODO find a better way to deal with soul sand!!!!!
065        BetterBlockPos feet = new BetterBlockPos(player().position().x, player().position().y + 0.1251, player().position().z);
066
067        // sometimes when calling this from another thread or while world is null, it'll throw a NullPointerException
068        // that causes the game to immediately crash
069        //
070        // so of course crashing on 2b is horribly bad due to queue times and logout spot
071        // catch the NPE and ignore it if it does happen
072        //
073        // this does not impact performance at all since we're not null checking constantly
074        // if there is an exception, the only overhead is Java generating the exception object... so we can ignore it
075        try {
076            if (world().getBlockState(feet).getBlock() instanceof SlabBlock) {
077                return feet.above();
078            }
079        } catch (NullPointerException ignored) {}
080
081        return feet;
082    }
083
084    default Vec3 playerFeetAsVec() {
085        return new Vec3(player().position().x, player().position().y, player().position().z);
086    }
087
088    default Vec3 playerHead() {
089        return new Vec3(player().position().x, player().position().y + player().getEyeHeight(), player().position().z);
090    }
091
092    default Vec3 playerMotion() {
093        return player().getDeltaMovement();
094    }
095
096    BetterBlockPos viewerPos();
097
098    default Rotation playerRotations() {
099        return new Rotation(player().getYRot(), player().getXRot());
100    }
101
102    /**
103     * Returns the player's eye height, taking into account whether or not the player is sneaking.
104     *
105     * @param ifSneaking Whether or not the player is sneaking
106     * @return The player's eye height
107     * @deprecated Use entity.getEyeHeight(Pose.CROUCHING) instead
108     */
109    @Deprecated
110    static double eyeHeight(boolean ifSneaking) {
111        return ifSneaking ? 1.27 : 1.62;
112    }
113
114    /**
115     * Returns the block that the crosshair is currently placed over. Updated once per tick.
116     *
117     * @return The position of the highlighted block
118     */
119    default Optional<BlockPos> getSelectedBlock() {
120        HitResult result = objectMouseOver();
121        if (result != null && result.getType() == HitResult.Type.BLOCK) {
122            return Optional.of(((BlockHitResult) result).getBlockPos());
123        }
124        return Optional.empty();
125    }
126
127    default boolean isLookingAt(BlockPos pos) {
128        return getSelectedBlock().equals(Optional.of(pos));
129    }
130}