/* * This file is part of Baritone. * * Baritone is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Baritone 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Baritone. If not, see . */ package baritone.pathing.movement; import baritone.Baritone; import baritone.api.IBaritone; import baritone.api.pathing.movement.ActionCosts; import baritone.cache.WorldData; import baritone.pathing.precompute.PrecomputedData; import baritone.utils.BlockStateInterface; import baritone.utils.ToolSet; import baritone.utils.pathing.BetterWorldBorder; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.item.Items; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.item.enchantment.Enchantments; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import java.util.ArrayList; import java.util.List; import static baritone.api.pathing.movement.ActionCosts.COST_INF; /** * @author Brady * @since 8/7/2018 */ public class CalculationContext { private static final ItemStack STACK_BUCKET_WATER = new ItemStack(Items.WATER_BUCKET); public final boolean safeForThreadedUse; public final IBaritone baritone; public final Level world; public final WorldData worldData; public final BlockStateInterface bsi; public final ToolSet toolSet; public final boolean hasWaterBucket; public final boolean hasThrowaway; public final boolean canSprint; protected final double placeBlockCost; // protected because you should call the function instead public final boolean allowBreak; public final List allowBreakAnyway; public final boolean allowParkour; public final boolean allowParkourPlace; public final boolean allowJumpAt256; public final boolean allowParkourAscend; public final boolean assumeWalkOnWater; public final int frostWalker; public final boolean allowDiagonalDescend; public final boolean allowDiagonalAscend; public final boolean allowDownward; public final int maxFallHeightNoWater; public final int maxFallHeightBucket; public final double waterWalkSpeed; public final double breakBlockAdditionalCost; public double backtrackCostFavoringCoefficient; public double jumpPenalty; public final double walkOnWaterOnePenalty; public final BetterWorldBorder worldBorder; public final PrecomputedData precomputedData; public CalculationContext(IBaritone baritone) { this(baritone, false); } public CalculationContext(IBaritone baritone, boolean forUseOnAnotherThread) { this.precomputedData = new PrecomputedData(); this.safeForThreadedUse = forUseOnAnotherThread; this.baritone = baritone; LocalPlayer player = baritone.getPlayerContext().player(); this.world = baritone.getPlayerContext().world(); this.worldData = (WorldData) baritone.getWorldProvider().getCurrentWorld(); this.bsi = new BlockStateInterface(world, worldData, forUseOnAnotherThread); this.toolSet = new ToolSet(player); this.hasThrowaway = Baritone.settings().allowPlace.value && ((Baritone) baritone).getInventoryBehavior().hasGenericThrowaway(); this.hasWaterBucket = Baritone.settings().allowWaterBucketFall.value && Inventory.isHotbarSlot(player.getInventory().findSlotMatchingItem(STACK_BUCKET_WATER)) && world.dimension() != Level.NETHER; this.canSprint = Baritone.settings().allowSprint.value && player.getFoodData().getFoodLevel() > 6; this.placeBlockCost = Baritone.settings().blockPlacementPenalty.value; this.allowBreak = Baritone.settings().allowBreak.value; this.allowBreakAnyway = new ArrayList<>(Baritone.settings().allowBreakAnyway.value); this.allowParkour = Baritone.settings().allowParkour.value; this.allowParkourPlace = Baritone.settings().allowParkourPlace.value; this.allowJumpAt256 = Baritone.settings().allowJumpAt256.value; this.allowParkourAscend = Baritone.settings().allowParkourAscend.value; this.assumeWalkOnWater = Baritone.settings().assumeWalkOnWater.value; this.frostWalker = EnchantmentHelper.getEnchantmentLevel(Enchantments.FROST_WALKER, baritone.getPlayerContext().player()); this.allowDiagonalDescend = Baritone.settings().allowDiagonalDescend.value; this.allowDiagonalAscend = Baritone.settings().allowDiagonalAscend.value; this.allowDownward = Baritone.settings().allowDownward.value; this.maxFallHeightNoWater = Baritone.settings().maxFallHeightNoWater.value; this.maxFallHeightBucket = Baritone.settings().maxFallHeightBucket.value; int depth = EnchantmentHelper.getDepthStrider(player); if (depth > 3) { depth = 3; } float mult = depth / 3.0F; this.waterWalkSpeed = ActionCosts.WALK_ONE_IN_WATER_COST * (1 - mult) + ActionCosts.WALK_ONE_BLOCK_COST * mult; this.breakBlockAdditionalCost = Baritone.settings().blockBreakAdditionalPenalty.value; this.backtrackCostFavoringCoefficient = Baritone.settings().backtrackCostFavoringCoefficient.value; this.jumpPenalty = Baritone.settings().jumpPenalty.value; this.walkOnWaterOnePenalty = Baritone.settings().walkOnWaterOnePenalty.value; // why cache these things here, why not let the movements just get directly from settings? // because if some movements are calculated one way and others are calculated another way, // then you get a wildly inconsistent path that isn't optimal for either scenario. this.worldBorder = new BetterWorldBorder(world.getWorldBorder()); } public final IBaritone getBaritone() { return baritone; } public BlockState get(int x, int y, int z) { return bsi.get0(x, y, z); // laughs maniacally } public boolean isLoaded(int x, int z) { return bsi.isLoaded(x, z); } public BlockState get(BlockPos pos) { return get(pos.getX(), pos.getY(), pos.getZ()); } public Block getBlock(int x, int y, int z) { return get(x, y, z).getBlock(); } public double costOfPlacingAt(int x, int y, int z, BlockState current) { if (!hasThrowaway) { // only true if allowPlace is true, see constructor return COST_INF; } if (isPossiblyProtected(x, y, z)) { return COST_INF; } if (!worldBorder.canPlaceAt(x, z)) { return COST_INF; } return placeBlockCost; } public double breakCostMultiplierAt(int x, int y, int z, BlockState current) { if (!allowBreak && !allowBreakAnyway.contains(current.getBlock())) { return COST_INF; } if (isPossiblyProtected(x, y, z)) { return COST_INF; } return 1; } public double placeBucketCost() { return placeBlockCost; // shrug } public boolean isPossiblyProtected(int x, int y, int z) { // TODO more protection logic here; see #220 return false; } }